5 - Funções

Modularização é o mecanismo para se dividir um programa em módulos. Um módulo é um trecho de programa que possui seus próprios objetos (variáveis, constantes, tipos) e que realizam uma tarefa específica. Para ser executado, um módulo precisa ser ativado pelo programa principal ou por um outro módulo.

As principais motivações para se modularizar um programa são: (a) evitar repetição de código; (b) dividir e estruturar melhor um algoritmo e (c) aumentar a legibilidade do código. A divisão de um programa em módulo traz os seguintes benefícios: (a) manutenção mais simples, pois os módulos são independentes; (b) elaboração e testes em separado e (c) reutilização do módulo em outros programas.

A ativação (ou chamada) de um módulo é o meio pelo qual é solicitado ao programa que desvie o fluxo de controle de execução para o módulo, execute suas instruções e depois volte à instrução seguinte à da chamada do módulo.

Em C/C++ a modularização é feita através das funções. As funções são módulos que podem receber valores externos, chamados parâmetros ou argumentos, e também podem retornar um valor produzido por ela chamado retorno.

Como descrito no capítulo 1.3, um programa C/C++ consiste na definição de uma ou mais funções, e que todo programa C/C++ deve possuir uma função chamada main. Abaixo temos a sintaxe de como definir uma função.

tipo nomedafuncao(declaração dos parâmetros)
{
    // instruções;
}

Neste capítulo será demonstrado como definir outras funções, além da função principal main, e como utilizar algumas funções predefinidas na biblioteca cmath do C/C++.

5.1 Funções Sem Passagem de Parâmetros e Sem Retorno

O tipo mais simples de função em C/C++ possui a sintaxe representada na figura a seguir.

funcao1.PNG

Esta função é simples pois não recebe nenhuma informação no momento de sua chamada (parâmetros) e também não retorna nenhum valor para quem a chamou. A forma de identificar que a função não retorna nenhuma informação é utilizando o tipo de retorno como void.

Exemplo 1

void  imprime( )
{
    cout<<”Teste de funcao”;
}

Chamada de função

A chamada de uma função é o meio pelo qual o programa é solicitado que desvie o controle e passe para a definição da função, execute suas instruções e depois volte à instrução seguinte a da chamada.

Chama-se uma função pelo seu nome seguido de abertura de parênteses, nenhum ou mais parâmetros sem os tipos, e o fechamento de parêntese. No exemplo abaixo, na linha 17, chama-se a função escrevendo-se soma().

Exemplo 2

Considere o seguinte programa que chama uma função soma que lê dois números digitados pelo usuário e imprime a sua soma.

#include<iostream>
using namespace std;
 
void soma()
{
  int n1,n2, s;
  cout<<"Digite o primeiro numero: "<<endl;
  cin>>n1;
  cout<<"Digite o segundo numero: "<<endl;
  cin>>n2;
  s = n1 + n2;
  cout<<"\n Soma = "<<s;
}
 
int main()
{
  soma(); // chamada da função
  return 0;
}

No exemplo, o programa começa sua execução na função main linha 15. Posteriormente, executa a linha 17 que possui uma chamada à função soma. Neste ponto, o fluxo de execução é desviado para a linha 4. Depois são executadas as linhas 4 até 12. Quando a execução chega na linha 13 é identificado o final da função e o fluxo de execução retorna para a linha 16, exatamente abaixo de onde ocorreu o desvio para a função soma. Em seguida é executada a linha 18 que retorna 0 para o sistema operacional.

Considere nas Tabelas seguintes o Teste de Mesa para uma entrada: n1 = 5 e n2 = 7.

Função main
Função Saída
linha void soma( )
17 desvio linha 4
18 retorna 0 para o sistema operacional
Função soma
Variáveis Saída
Linha n1 n2 s
4
5
6 lixo lixo lixo
7 .. .. .. Digite o primeiro numero:
8 5 .. ..
9 .. .. .. Digite o segundo numero:
10 .. 7 ..
11 .. .. 12
12 .. .. .. Soma = 12
volta para linha 17

No teste de mesa acima, cada função possui sua própria tabela, representando exatamente o escopo das variáveis, ou seja, o local onde cada variável existe durante o processo de execução.

Para simplificar a construção da tabela, utiliza-se " (aspas duplas) ou .. (dois pontos) nas linhas subsequentes quando não houver alteração dos valores das variáveis, desta forma é possível saber o ponto exato onde elas foram modificadas.

Protótipo da Função

Note que no exemplo acima o código da função foi definido antes da função main. Em C/C++ também é possível escrever funções depois da função main, desde que se defina o protótipo da função antes da função main.

O protótipo da função tem a mesma forma de definição da função, exceto por terminar com ponto-e-vírgula após o fechamento do parêntese. No exemplo abaixo, na linha 4, é demonstrado o uso do protótipo.

Exemplo 3

#include<iostream>
using namespace std;
 
void soma(); //protótipo da função
 
int main()
{
  soma();
  return 0;
}
 
void soma()
{
  int n1,n2, s;
  cout<<"Digite o primeiro numero: "<<endl;
  cin>>n1;
  cout<<"Digite o segundo numero: "<<endl;
  cin>>n2;
  s = n1 + n2;
  cout<<"\n Soma = "<<s;
}

5.2 Funções Com Passagem de Parâmetros e Sem Retorno

O segundo tipo de função é representado por aquelas que recebem valores no momento em que são chamadas (parâmetros) e não retorna valor para quem as chamou (void). A sintaxe está representada na figura abaixo.

funcao2.PNG

Exemplo 1

No exemplo abaixo é definida uma função que receberá dois parâmetros (string e int) no momento de sua chamada.

void welcome(string nome, int idade)
{
  cout<<"Bem vindo(a)\nNome:"<<nome<<endl<<"Idade:"<<idade;
}

Os parâmetros da função são variáveis locais, portanto, podem ser usados dentro da função. Eles são usados como um meio para comunicação entre as funções pois recebem (ou retornam) valores de outras funções.

Exemplo 2

Considere o seguinte programa que chama uma função soma com dois parâmetros do tipo int e imprime a sua soma.

#include<iostream>
using namespace std;
 
void soma(int n1, int n2)
{
  int s;
  s = n1 + n2;
  cout<<"\n Soma = "<<s;
}
 
int main()
{
  int numero1, numero2;
  cout<<"Digite o primeiro numero: "<<endl;
  cin>>numero1;
  cout<<"Digite o segundo numero: "<<endl;
  cin>>numero2;
  soma(numero1,numero2); //chamada da função
  return 0;
}

No exemplo, o programa começa sua execução na função main linha 11. Posteriormente, executa as linhas 12 a 17 onde recebe do usuário dois números. Depois executa a linha 18 que possui uma chamada à função soma onde é passado como parâmetro o valor das variáveis numero1 e numero2. Neste ponto, o fluxo de execução é desviado para a linha 4, neste momento os valores de numero1 e numero2 são copiados para as variáveis locais n1 e n2, respectivamente. Depois são executadas as linhas 5 até 8. Quando a execução chega na linha 9 é identificado o final da função e o fluxo de execução retorna para a linha 18, exatamente abaixo de onde ocorreu o desvio para a função soma. Em seguida é executada a linha 19 que retorna 0 para o sistema operacional.

Considere nas Tabelas seguintes o Teste de Mesa para uma entrada: numero1 = 10 e numero2 = 6.

Função main
Variáveis Função Saída
linha numero1 numero2 void soma(int, int)
13 lixo lixo
14 .. .. Digite o primeiro numero:
15 10 ..
16 .. .. Digite o segundo numero:
17 .. 6
18 .. .. soma(10,6) — desvio linha 4
19 retorna 0 para o sistema operacional
Função soma
Variáveis Saída
Linha n1 n2 s
4 10 6
5 .. ..
6 .. .. lixo
7 .. .. 16
8 .. .. .. Soma = 16
volta para linha 18

Observações:

  • Caso a função fosse definida após a função main o protótipo seria void soma(int n1, int n2);.
  • Na chamada da função, pode-se invocar a função passando valores do tipo dos parâmetros. Exemplo soma(7,8);.
  • A ordem e o tipo dos parâmetros devem ser respeitados na chamada da função.

5.3 Funções Sem Passagem de Parâmetros e Com Retorno

O terceiro tipo de função não recebe valores no momento em que são chamadas mas retornam um valor para quem a chamou (retorno). A sintaxe está representada na figura abaixo.

funcao3.PNG

O tipo de retorno pode ser qualquer tipo de dado apresentado no Capítulo 2.2 (int, float, char, string , …). Exemplo: a função main possui o tipo de retorno int que é devolvido para o sistema operacional.

O retorno da função é feito através do comando return. Este comando ao ser processado termina a execução da função e retorna o controle para a instrução seguinte do código da chamada. Nas funções onde o tipo de retorno é void pode-se utilizar o comando return; e nas demais funções o comando return tipodeRetorno;. No exemplo abaixo na linha 12 é demonstrado o uso do return.

Exemplo

Considere o seguinte programa que chama uma função soma sem parâmetros e retorna um valor inteiro (int) para a função que a chamou.

#include<iostream>
using namespace std;
 
int soma()
{
  int n1,n2,s;
  cout<<"Digite o primeiro numero: "<<endl;
  cin>>n1;
  cout<<"Digite o segundo numero: "<<endl;
  cin>>n2;
  s = n1 + n2;
  return s;
}
 
int main()
{
  int resultado;
  resultado=soma();
  cout<<"\n Soma = "<<resultado;
  return 0;
}

No exemplo, o programa começa sua execução na função main linha 15 e executa as linhas 16 e 17. Depois executa a linha 18 que possui uma chamada à função soma sem parâmetro que após a sua execução atribuir o seu retorno para a variável resultado. Neste ponto, o fluxo de execução é desviado para a linha 4 onde são executados as linhas de 4 até 11. Quando a execução chega na linha 12 é acionado o comando return que retorna o valor de s para quem chamou a função terminando a sua execução. O fluxo de execução retorna para a linha 19 após a variável resultado (linha 18) ter recebido o resultado da função. A linha 19 é executada e imprime a soma na tela e em seguida a linha 20 que retorna 0 para o sistema operacional.

Considere nas Tabelas seguintes o Teste de Mesa para a entrada: n1 = 7 e n2 = 5.

Função main
Variáveis Função Saída
linha resultado int soma( )
17 lixo
18 12 soma( ) —
desvio linha 4
19 .. Soma = 12
20 retorna 0 para o sistema operacional
Função soma
Variáveis Saída
Linha n1 n2 s
4
5
6 lixo lixo lixo
7 .. .. .. Digite o primeiro numero:
8 7 .. ..
9 .. .. .. Digite o segundo numero:
10 .. 5 ..
11 .. .. 12
12 Retorna o valor 12 e volta para linha 18

Observações:

  • Podemos utilizar mais de um comando return na mesma função.
  • O informação retornada pelo comando return deve ser do mesmo tipo definido na função.

5.4 Funções Com Passagem de Parâmetros e Com Retorno

O quarto tipo de função é representado por aquelas que recebem valores no momento em que são chamadas (parâmetros) e retornam um valor para quem a chamou (retorno). A sintaxe está representada na figura abaixo.

funcao4.PNG

Exemplo

Considere o seguinte programa que chama uma função soma com dois parâmetros do tipo int e retorna um valor inteiro (int) contendo a soma para a função que a chamou.

#include<iostream>
using namespace std;
 
int soma(int n1, int n2)
{
  int s;
  s = n1 + n2;
  return s;
}
 
int main()
{
  int numero1, numero2, resultado;
  cout<<"Digite o primeiro numero: "<<endl;
  cin>>numero1;
  cout<<"Digite o segundo numero: "<<endl;
  cin>>numero2;
  resultado=soma(numero1,numero2);
  cout<<"\n Soma = "<<resultado;
  return 0;
}

No exemplo, o programa começa sua execução na função main linha 11. Posteriormente, executa as linhas 12 a 17 onde recebe do usuário dois números. Depois executa a linha 18 que possui uma chamada à função soma onde é passado como parâmetro o valor das variáveis numero1 e numero2. Neste ponto, o fluxo de execução é desviado para a linha 4, neste momento os valores de numero1 e numero2 são copiados para as variáveis locais n1 e n2, respectivamente. Depois são executados as linhas 5 até 7. Quando a execução chega na linha 8 é acionado o comando return que retorna o valor de s para quem chamou a função terminando a sua execução. O fluxo de execução retorna para a linha 19 após a variável resultado (linha 18) ter recebido o resultado da função soma. A linha 19 é executada e imprime a soma na tela e em seguida a linha 20 que retorna 0 para o sistema operacional.

Considere nas Tabelas seguintes o Teste de Mesa para a entrada: numero1 = 3 e numero2 = 4.

Função main
Variáveis Função Saída
linha numero1 numero2 resultado int soma(int, int)
13 lixo lixo lixo
14 .. .. .. Digite o primeiro numero:
15 3 .. ..
16 .. .. .. Digite o segundo numero:
17 .. 4 ..
18 .. .. 7 soma(3,4) — desvio linha 4
19 .. .. .. Soma = 7
20 retorna 0 para o sistema operacional
Função soma
Variáveis Saída
Linha n1 n2 s
4 3 4
5 .. ..
6 .. .. lixo
7 .. .. 7
8 Retorna o valor 7 e volta para linha 18

5.5 Passagem de Parâmetros Por Valor e Por Referência

A passagem de parâmetros pode ser feita de duas formas, por valor e por referência.

Passagem de Parâmetro Por Valor

A passagem de parâmetros por valor significa que a função trabalhará com cópias dos valores passados no momento de sua chamada, desta forma, qualquer alteração dos valores nas variáveis correspondentes dentro da função não afetam os valores das variáveis utilizadas como parâmetros. Até este momento todas as funções apresentadas utilizam a passagem de parâmetros por valor.

Passagem de Parâmetro Por Referência

A passagem de parâmetros por referência significa que a função trabalhará com as próprias variáveis passadas no momento de sua chamada. Assim, qualquer alteração nos valores das variáveis correspondentes dentro da função afetam as variáveis passadas como parâmetros.

Este mecanismo permite que a função retorne mais de um valor para a função que chama.

Para definir que um parâmetro será passado como referência para uma função, utilizamos o símbolo & antes do nome da variável no cabeçalho da função, indicando que ela é um alias (apelido, referência, outro nome) para a variável passada como parâmetro. Veja os exemplos abaixo.

Exemplo 1

Neste exemplo, o parâmetro a será a própria variável (passagem de parâmetro por referência) e o parâmetro b receberá uma cópia da variável (passagem de parâmetro por valor).

double operacaoX(double  &a, int b)
{
    //instruções
}

Exemplo 2

Considere o programa abaixo que chama uma função nao_muda e a função muda.

#include<iostream>
using namespace std;
 
void nao_muda(int a, double b)   //passagem por valor
{
   a+=2;    // significa a=a+2;
   b+=5;    // significa b=b+5;
}
 
void muda(int &a, double &b)     //passagem por referência
{
   a+=2;
   b+=5;
}
 
int main()
{
  int n1=5;
  double n2=6.0;
  cout<<"n1 = "<<n1<<" n2 = "<<n2<<endl;
  nao_muda(n1,n2);
  cout<<"Valores apos a funcao nao_muda n1 = "<<n1<<" n2 = "<<n2<<endl;
  muda(n1,n2);
  cout<<"Valores apos a funcao muda n1 = "<<n1<<" n2 = "<<n2<<endl;
  return 0;
}

No exemplo, o programa começa sua execução na função main linha 16. Posteriormente, executa as linhas 17 a 19 onde as variáveis n1 e n2 recebem dois valores e a linha 20 que apresenta na tela os valores de n1 e n2. Em seguida, executa a linha 21 que possui uma chamada à função nao_muda onde são passados como parâmetros os valores das variáveis n1 e n2. Neste ponto, o fluxo de execução é desviado para a linha 4, neste momento os valores de n1 e n2 são copiados para as variáveis locais a e b, respectivamente. Depois são executadas as linhas 5 a 7 que modificam os valores das variáveis locais a e b. Quando a execução chega na linha 8 é alcançado o fim da função e o fluxo de execução retorna para a linha 22. Na linha 22 são apresentados na tela os valores de n1 e n2 com os mesmos valores apresentados na linha 20. Depois é executada a linha 23 que possui uma chamada à função muda onde são passados como parâmetros as variáveis n1 e n2. Um desvio do fluxo de execução é feito para a linha 10, neste momento é criada a referência das variáveis n1 e n2 para as variáveis a e b, respectivamente. Depois são executadas as linhas 11 a 13 que modificam os valores das variáveis locais a e b que são as variáveis n1 e n2 com nomes diferentes. Quando a execução chega na linha 14 é alcançado o fim da função e o fluxo de execução retorna para a linha 24. Na linha 24 são apresentados na tela os valores de n1 e n2 agora com novos valores. E por fim, é executada a linha 25 que retorna 0 para o sistema operacional.

Considere nas Tabelas seguintes o Teste de Mesa para a entrada: n1 = 5 e n2 = 6.0.

Função main
Variáveis Função Saída
linha n1 n2 void nao_muda(int, int) void muda(&int, &int)
18 5
19 .. 6.0
20 .. .. n1=5 n2=6.0
21 .. .. nao_muda(5, 6.0) —
desvio linha 4
22 .. .. Valores após a funcao nao_muda n1 = 5 n2 = 6.0
23 7 11.0 muda(n1, n2) —
desvio linha 10
24 .. .. Valores apos a funcao muda n1=7 n2=11.0
25 retorna 0 para o sistema operacional
Função nao_muda
Variáveis Saída
Linha a b
4 5 6.0
5 .. ..
6 7 ..
7 .. 11.0
volta para linha 21
Função muda
Variáveis Saída
Linha &a &b
10 5 6.0
11 .. ..
12 7 ..
13 .. 11.0
volta para linha 23

5.6 Funções Predefinidas

Em C/C++ existem várias bibliotecas com funções predefinidas. Uma das bibliotecas mais úteis é a biblioteca matemática cmath ou math.h . Abaixo alguns exemplos.

função Comentário Protótipo
ceil(x) Arredonda um número real para cima. double ceil ( double x );
float ceil ( float x );
cos(x) Calcula o cosseno de x (em radianos). double cos ( double x );
float cos ( float x );
exp(x) Obtém o número natural e elevado à potência x. double exp ( double x );
float exp ( float x );
fabs(x) Obtém o valor absoluto de x. double fabs ( double x );
float fabs ( float x );
floor(x) Arredonda um número real para baixo. double floor ( double x );
float floor ( float x );
log(x) Obtém o logaritmo natural de x. double log ( double x );
float log ( float x );
log10(x) Obtém o logaritmo de base 10 de x. double log10 ( double x );
float log10 ( float x );
pow(x,y) Calcula a potência de x elevado a y. double pow ( double base, double exponent );
float pow ( float base, float exponent );
double pow ( double base, int exponent );
sen(x) Calcula o seno de x (em radianos) double sin ( double x );
float sin ( float x );
sqrt(x) Calcula a raiz quadrada de x. double sqrt ( double x );
float sqrt ( float x );

Exemplo 1

#include<iostream>
#include<cmath>
using namespace std;
 
int main()
{
  double base, expoente, resultado;
  cout<<"Digite a base de um numero exponencial";
  cin>>base;
  cout<<"Digite o expoente de um numero exponencial";
  cout<<expoente;
  resultado = pow(base,expoente); 
  cout<<"O valor do numero exponencial e = "<<resultado;
  return 0;
}

Exemplo 2

#include<iostream>
#include<cmath>
using namespace std;
 
int main()
{
  double numero, raiz;
  cout<<"Digite um numero";
  cin>>numero;
  raiz = sqrt(numero); 
  cout<<"A raiz quadrada de "<<numero<<" e " <<raiz;
  return 0;
}

5.7 Exercícios

  1. Escreva uma função que receba como argumento o ano e retorne true se for um ano bissexto e false se não for. Um ano é bissexto se for divisível por 4, mas não por 100. Um ano também é bissexto se for divisível por 400.
  2. Escreva uma função que receba um número float como argumento e retorne, em outros dois argumentos passados por referência, a parte inteira e a parte decimal desse número.
  3. Escreva uma função que ordene o valor de três argumentos do tipo char. Por exemplo, se ch1, ch2, ch3 são variáveis do tipo char com valores, respectivamente 'B', 'A' e 'C', após a chamada à função, as variáveis conterão, respectivamente, 'A', 'B' e 'C'.
  4. Escreva uma função chamada maior que receba 2 números inteiros e retornará o maior deles.
  5. Escreva uma função chamada maior3 que receba 3 números inteiros e utilizando a função maior do exercício 4, retorne o maior deles.
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License