Mudanças entre as edições de "Funções - Programação 1 - Engenharia"

De MediaWiki do Campus São José
Ir para navegação Ir para pesquisar
(48 revisões intermediárias pelo mesmo usuário não estão sendo mostradas)
Linha 1: Linha 1:
 +
= Objetivos da Aula =
 +
 +
*Conceituar funções, parâmetros e valor de retorno;
 +
 +
*Definir, declarar e chamar funções no C;
 +
 +
*Declarar protótipo de funções;
 +
 +
*Distinguir e saber criar variáveis locais e globais;
 +
 +
*Aplicar funções para resolver subproblemas de um grande problema;
 +
 +
*Noção de recursividade e o cuidado no uso...
 +
 +
= Referências Históricas =
 +
 +
*[https://en.wikipedia.org/wiki/Single-responsibility_principle  O Princípio da Responsabilidade Única]
 +
 +
= Conceito de Função =
 +
 +
Uma função é um "bloco de código" que resolve um dado problema
 +
específico,  que possui um nome associado e
 +
que pode ser chamado quando necessário. Ao final da função a linha de execução
 +
retorna para quem chamou a função.
 +
 +
Exemplo: para calcular o seno de um ângulo chamamos uma função para resolver
 +
o problema específico: "calcular um seno". Dados de entrada devem ser fornecidos,
 +
no caso o ângulo. O dado de saída é o seno computado deste ângulo.
 +
 +
Notar que a função permite REAPROVEITAR o código. Não precisamos a todo momento
 +
reescrever um código que computa o seno. Basta chamar a função.
 +
 
= FUNÇÕES no C =
 
= FUNÇÕES no C =
  
Linha 62: Linha 94:
 
NOTAR que existem 3 momentos diferentes de uso de funções:
 
NOTAR que existem 3 momentos diferentes de uso de funções:
  
*Definição de função: é quando se constrói a função explicitando o seu nome, tipo de retorno, parâmetros e o seu corpo (instruções e variáveis locais;
+
*'''Definição de função''': é quando se constrói a função explicitando o seu nome, tipo de retorno, parâmetros e o seu corpo (instruções e variáveis locais;
*Declaração da Função: é somente uma declaração contendo o nome da função, tipo de retorno e parâmetros. O corpo da função NÂO é explicitado pois supõe-se que ela foi definida em algum outro lugar;
+
*'''Declaração da Função''': é somente uma declaração contendo o nome da função, tipo de retorno e parâmetros. O corpo da função NÂO é explicitado pois supõe-se que ela foi definida em algum outro lugar;
*Chamada (invocação) da Função: quando se usa a função, chamando-a pelo seu nome e passando os parâmetros (ATUAIS) que se deseja.
+
*'''Chamada (invocação) da Função''': quando se usa a função, chamando-a pelo seu nome e passando os parâmetros (ATUAIS) que se deseja.
  
 
==Por que usar Funções==
 
==Por que usar Funções==
Linha 76: Linha 108:
  
 
<blockquote style="background: #DCF4CC; border: 1px solid black; padding: 1em;">
 
<blockquote style="background: #DCF4CC; border: 1px solid black; padding: 1em;">
CONSELHO: SEMPRE que receber um problema a ser resolvido, tente quebrá-lo em subproblemas com "funcionalidades" bem definidas. Pense seriamente rm tratar cada subproblema como uma ou mais funções. Liste os possíveis parâmetros e o retorno destas funções. Agrupe as funções em módulos (serão arquivos furutamente).
+
CONSELHO: SEMPRE que receber um problema a ser resolvido, tente quebrá-lo em subproblemas com "funcionalidades" bem definidas. Pense seriamente rm tratar cada subproblema como uma ou mais funções. Liste os possíveis parâmetros e o retorno destas funções. Agrupe as funções em módulos (serão arquivos fututamente).
 
</blockquote>
 
</blockquote>
  
Linha 116: Linha 148:
 
       srand ( time(NULL) );
 
       srand ( time(NULL) );
  
       teste = somar_2_dados();
+
       teste = somar_dois_dados();
 
       printf("Valor da jogada de dados é %d\n", teste);
 
       printf("Valor da jogada de dados é %d\n", teste);
 
       return 0;
 
       return 0;
Linha 165: Linha 197:
  
 
/******************************************/
 
/******************************************/
main()
+
int main()
 
{  
 
{  
 
   int opcao;
 
   int opcao;
Linha 299: Linha 331:
 
{{collapse bottom}}
 
{{collapse bottom}}
  
==Passando parâmetros e recebendo valores de retorno==
+
=Passando parâmetros e recebendo valores de retorno=
  
 
Uma função normalmente resolve um determinado problema para um determinado conjunto de dados e produz uma saída. Estes dados podem ser passados como parâmetros e a saída pode ser retornada pela função.
 
Uma função normalmente resolve um determinado problema para um determinado conjunto de dados e produz uma saída. Estes dados podem ser passados como parâmetros e a saída pode ser retornada pela função.
  
Exemplo: Uma função ''media_nums''() que retorna a média de 3 números reais passados como parâmetros  
+
Exemplo: Uma função ''media_nums''() que retorna a média de 3 números reais passados como parâmetros. Note que se trata de
 +
um exemplo pois NÃO seria necessário uma função para esta finalidade.
  
 
<syntaxhighlight lang=c>
 
<syntaxhighlight lang=c>
Linha 346: Linha 379:
 
NOTE que o formato de declaração de uma função é
 
NOTE que o formato de declaração de uma função é
  
   tipo_retorno nome_funcao( lista_de_parametros )
+
   ''tipo_retorno'' '''nome_funcao'''( ''lista_de_parametros'' )
 
   {
 
   {
 
     declaracao_variaveis_locais
 
     declaracao_variaveis_locais
+
    lista_instruções
     instruções
+
     return; /* comando de retorno - pode ou não retornar valor - pode ser omitido */
 
   }
 
   }
  
Por enquanto, assumiremos que variáveis devem ser somente declaradas no início da função. Existem situações que poderemos relaxar esta afirmação.
+
Por enquanto, assumiremos que variáveis devem ser somente declaradas no início da função (logo após a abertura do bloco com '{'. Existem situações que poderemos relaxar esta afirmação.
 +
 
 +
U ponto a ser observado é a questão do retorno de uma função. Se a função não retorna um valor então tipo de retorno deve ser '''void'''. Neste caso, para realizar o retorno no código deve ser usada a palavra reservada '''return'''.
  
 
==Um pouco mais sobre parâmetros==
 
==Um pouco mais sobre parâmetros==
  
O termo ''argumento'' ou ''parâmetro real'' (atual) é usado para referenciar os valores que estão sendo passados na CHAMADA da função. Os ''parâmetros formais'' referem-se aos parâmetros listados na função. É comum, no entanto, usar os termos argumentos e parâmetros como sinônimos e identificados pelo contexto em que estão sendo usados.
+
<blockquote style="background: #DCF4CC; border: 1px solid black; padding: 1em;">
 +
O termo '''argumento''' ou '''parâmetro real''' (atual) é usado para referenciar os valores que estão sendo passados na CHAMADA da função. Os '''parâmetros formais''' referem-se aos parâmetros listados na função. É comum, no entanto, usar os termos argumentos e parâmetros como sinônimos e identificados pelo contexto em que estão sendo usados.
 +
</blockquote>
 +
 
 +
<blockquote style="background: #DCF4CC; border: 1px solid black; padding: 1em;">
 +
A passagem de parâmetros POR VALOR diz respeito a copiar o valor do argumento na CHAMADA da função para a variável associada ao parâmetro na função. Mais tarde falaremos na passagem de parâmetro POR REFERÊNCIA. Neste último é repassado o endereço da variável para a função. Por ora, usaremos a passagem POR VALOR.
 +
</blockquote>
  
A passagem de parâmetros POR VALOR diz respeito a copiar o valor do argumento na CHAMADA da função para a variável associada ao parâmetro na função. Mais tarde falaremos na passagem de parâmetro POR REFERÊNCIA. Por ora, usaremos a passagem
 
POR VALOR.
 
  
 
Os parâmetros passados na CHAMADA de uma função não são necessariamente variáveis.
 
Os parâmetros passados na CHAMADA de uma função não são necessariamente variáveis.
Linha 368: Linha 407:
  
 
<syntaxhighlight lang=c>
 
<syntaxhighlight lang=c>
 +
#include <stdio.h>
 +
 +
/* OBS: num1, m2 e num3 são os parâmetros formais */
 +
float media_nums(float num1, float num2, float num3)
 +
{
 +
  float media_local;
  
main()
+
  media_local = (num1 + num2 + num3)/3;
 +
  return media_local;
 +
}
 +
 
 +
int main()
 
{
 
{
 
   float media, x,y,z;
 
   float media, x,y,z;
Linha 381: Linha 430:
 
   /* exemplo de chamada 2 */  
 
   /* exemplo de chamada 2 */  
 
   media = media_nums (x+y,y*y+5,(x+y)/2);
 
   media = media_nums (x+y,y*y+5,(x+y)/2);
 +
  return 0;
 
}
 
}
 
</syntaxhighlight>
 
</syntaxhighlight>
Linha 388: Linha 438:
 
* na chamada 2 aparecem expressões ainda mais complexas. Todas elas devem ser resolvidas antes da função ser INVOCADA.
 
* na chamada 2 aparecem expressões ainda mais complexas. Todas elas devem ser resolvidas antes da função ser INVOCADA.
  
==Funções Definidas pelo Usuário X Funções da Biblioteca==
+
=Funções Definidas pelo Usuário X Funções da Biblioteca=
  
 
*Existem funções que já foram implementadas e disponibilizadas através de uma biblioteca.  
 
*Existem funções que já foram implementadas e disponibilizadas através de uma biblioteca.  
Linha 398: Linha 448:
  
 
<blockquote style="background: #DCF4CC; border: 1px solid black; padding: 1em;">
 
<blockquote style="background: #DCF4CC; border: 1px solid black; padding: 1em;">
EXERCÍCIO EM SALA: IMPLEMENTAR uma função para retornar a soma de dois dados lançados randomicamente.
+
EXERCÍCIO EM SALA: IMPLEMENTAR uma função para retornar a soma de N dados lançados randomicamente.
  
 
Perguntas a serem respondidas antes de começar a implementação:
 
Perguntas a serem respondidas antes de começar a implementação:
 
*Qual é a funcionalidade desta função? Qual o objetivo dela?  
 
*Qual é a funcionalidade desta função? Qual o objetivo dela?  
*Esta função tem parâmetros? Em que situação ela poderia ter parâmetros?
+
*Esta função tem parâmetros?
*A função retorna valor? Que tipo?
+
*A função retorna valor? De que tipo?
 
*Liste possíveis variações desta função.
 
*Liste possíveis variações desta função.
**somar o lançamento de N dados;
 
**criar um dado de N faces...
 
 
</blockquote>
 
</blockquote>
  
==Variáveis GLOBAIS e variáveis LOCAIS ==
+
=Variáveis GLOBAIS e variáveis LOCAIS =
  
 +
<blockquote style="background: #DCF4CC; border: 1px solid black; padding: 1em;">
 
Se variáveis são declaradas dentro de uma função, então a visibilidade (ESCOPO) destas variáveis é LOCAL. Nenhuma outra função tem acesso a estas variáveis.
 
Se variáveis são declaradas dentro de uma função, então a visibilidade (ESCOPO) destas variáveis é LOCAL. Nenhuma outra função tem acesso a estas variáveis.
 
Na realidade, o ESCOPO da variáivel LOCAL é o bloco (entre chaves) em que ela foi declarada.
 
Na realidade, o ESCOPO da variáivel LOCAL é o bloco (entre chaves) em que ela foi declarada.
  
Uma variável pode ser GLOBAL, ou seja, declarada FORA das funções. Neste caso a variável é VISTA por todas as funções. Seja o exemplo anterior modiificado:
+
Uma variável pode ser GLOBAL, ou seja, declarada FORA das funções. Neste caso a variável é VISTA por todas as funções.
 +
 
 +
Uma BOA PRÁTICA é evitar o uso de variáveis GLOBAIS para minimizar possibilidade de erros nos programas.
 +
</blockquote>
 +
 
 +
Seja o exemplo anterior modificado:
  
 
<syntaxhighlight lang=c>
 
<syntaxhighlight lang=c>
Linha 427: Linha 481:
 
}
 
}
  
main()
+
int main()
 
{
 
{
 
   float aux1, aux2, aux3; /* Variáveis LOCAIS */
 
   float aux1, aux2, aux3; /* Variáveis LOCAIS */
Linha 442: Linha 496:
 
   media_nums(aux1, aux2, aux3);
 
   media_nums(aux1, aux2, aux3);
 
   printf ("\nmedia dos 3 numeros é %f\n", media);
 
   printf ("\nmedia dos 3 numeros é %f\n", media);
 +
  return 0;
 
}
 
}
  
Linha 454: Linha 509:
 
  no lado direito do sinal de atribuição.
 
  no lado direito do sinal de atribuição.
  
Na realidade, uma função pode ser chamada dentro de qualquer expressão. Por exemplo,
+
OBSERVAR que uma função pode ser chamada dentro de qualquer expressão. Por exemplo,
 
para o caso em que a função ''media_nums()'' retorna um valor, ela poderia ser usada como:
 
para o caso em que a função ''media_nums()'' retorna um valor, ela poderia ser usada como:
  
Linha 468: Linha 523:
 
}
 
}
  
main()
+
int main()
 
{
 
{
 
   float media, aux1, aux2, aux3;
 
   float media, aux1, aux2, aux3;
Linha 482: Linha 537:
 
   media = media_nums(aux1, aux2, aux3);
 
   media = media_nums(aux1, aux2, aux3);
 
   printf ("\nmedia dos 3 numeros multiplicada por 10 é %f\n", 10*media_nums(aux1, aux2, aux3));
 
   printf ("\nmedia dos 3 numeros multiplicada por 10 é %f\n", 10*media_nums(aux1, aux2, aux3));
 +
  return 0;
 
}
 
}
 
</syntaxhighlight>
 
</syntaxhighlight>
Linha 487: Linha 543:
 
== Um parênteses sobre nome de variáveis ==
 
== Um parênteses sobre nome de variáveis ==
  
Um nome de variável pode conter letras, dígitos e o ''underscore''(sublinhado). Ela DEVE iniciar com um ''underscore'' ou uma letra. Letras maúsculas e minúsculas podem ser usadas e são distinguidas (o C é ''CASE SENSITIVE'')  
+
*Um nome de variável pode conter letras, dígitos e o ''underscore''(sublinhado). Ela DEVE iniciar com um ''underscore'' ou uma letra.  
+
*Letras maúsculas e minúsculas podem ser usadas e são distinguidas (o C é ''CASE SENSITIVE'')  
Variáveis LOCAIS e GLOBAIS podem ter o mesmo nome. A variável LOCAL terá preferência no uso.  
+
*Variáveis LOCAIS e GLOBAIS podem ter o mesmo nome. A variável LOCAL terá preferência no uso.  
  
 
Exercício: Execute o programa abaixo e verifique as saídas.
 
Exercício: Execute o programa abaixo e verifique as saídas.
Linha 534: Linha 590:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
   NOTA: variáveis LOCAIS não são iniciadas automaticamente: cabe ao programador iniciá-la corretamente.
+
   NOTA: variáveis LOCAIS não são iniciadas automaticamente com zero. Cabe ao programador iniciá-la corretamente.
  
 
   NOTA: variáveis GLOBAIS são iniciadas automaticamente com zero.  
 
   NOTA: variáveis GLOBAIS são iniciadas automaticamente com zero.  
Linha 540: Linha 596:
 
         Em sistemas embarcados pode não ser verdade!
 
         Em sistemas embarcados pode não ser verdade!
  
==Exercícios==
+
=Exercícios=
  
 
<ol>
 
<ol>
<li>
 
Elaborar uma função que imprime uma mensagem:<br />
 
'''ATENÇÃO: CUIDADO COM O CORONA!!!'''<br />
 
Customize a função para que ela '''repita a mensagem N vezes''', onde N é passado como parâmetro. Será que seri importante a função retornar um valor?
 
</li>
 
 
<li>
 
Elaborar uma função "linha_vazada()" para desenhar uma linha da forma:<syntaxhighlight>
 
XXbbbbbbbbbbbXX
 
</syntaxhighlight>
 
O caracter b apenas indica espaço em branco.
 
Qual seria o tipo de retorno desta '''função'''?
 
 
Quais parâmetros ela tem?
 
Propor uma versão customizada que proporcione receber como parâmetros a largura<br />
 
total da linha (número de espaços em branco) mas mantendo sempre os lados com XX.
 
 
</li>
 
  
 
<li>
 
<li>
Linha 569: Linha 607:
  
 
{{collapse top | Solução}}
 
{{collapse top | Solução}}
 +
<!--
 
<syntaxhighlight lang=c>
 
<syntaxhighlight lang=c>
 
#include <stdio.h>
 
#include <stdio.h>
Linha 602: Linha 641:
 
}
 
}
 
</syntaxhighlight>
 
</syntaxhighlight>
 +
-->
 
{{collapse bottom}}
 
{{collapse bottom}}
  
Linha 612: Linha 652:
  
 
{{collapse top | Solução}}
 
{{collapse top | Solução}}
 +
<!--
 
<syntaxhighlight lang=c>
 
<syntaxhighlight lang=c>
 
#include <stdio.h>
 
#include <stdio.h>
Linha 634: Linha 675:
 
}
 
}
 
</syntaxhighlight>
 
</syntaxhighlight>
 +
-->
 
{{collapse bottom}}
 
{{collapse bottom}}
 
</li>
 
</li>
Linha 642: Linha 684:
  
 
{{collapse top | Solução}}
 
{{collapse top | Solução}}
 +
<!--
 
<syntaxhighlight lang=c>
 
<syntaxhighlight lang=c>
 
#include <stdio.h>
 
#include <stdio.h>
Linha 683: Linha 726:
 
}
 
}
 
</syntaxhighlight>
 
</syntaxhighlight>
 +
-->
 
{{collapse bottom}}
 
{{collapse bottom}}
  
 
</li>
 
</li>
 +
 +
<li>
 +
Faça uma função para calcular o módulo de um número complexo passado na forma retangular. O protótipo da função tem o seguinte aspecto:
 +
<syntaxhighlight lang=c>
 +
float mod_complexo(float x, float y)
 +
</syntaxhighlight>
 +
 +
{{collapse top | Solução}}
 +
<!--
 +
<syntaxhighlight lang=c>
 +
#include <stdio.h>
 +
#include <math.h>
 +
 +
float mod_complexo(float x,float y)
 +
{
 +
  float modulo;/* Variaveis LOCAIS */
 +
  modulo = sqrt( ((x*x) + (y*y)) ); // Funcao sqrt lembrar de utilizar math.h
 +
  return modulo;
 +
}
 +
 +
main()
 +
{
 +
  float num1, num2, result;/* Variaveis LOCAIS */
 +
  printf("Entre com a parte real:\n");
 +
  scanf("%f",&num1);
 +
  printf("Entre com a parte imaginaria:\n");
 +
  scanf("%f",&num2);
 +
  result = mod_complexo(num1,num2);
 +
  printf("Modulo do numero complexo: %f\n",result);
 +
 +
}
 +
</syntaxhighlight>
 +
-->
 +
{{collapse bottom}}
 +
</li>
 +
 +
<li>
 +
Elaborar uma função que recebe uma temperatura em graus em Fahrenheit e retorna graus celsius.
 +
</li>
 +
 +
<li>
 +
Elaborar uma função que calcula o índice massa corporal. Quais seriam os parâmetros da função?
 +
</li>
 +
  
 
<li>
 
<li>
Linha 810: Linha 898:
 
</li>
 
</li>
  
<li>
 
Faça uma função para calcular o módulo de um número complexo passado na forma retangular. O protótipo da função tem o seguinte aspecto:
 
<syntaxhighlight lang=c>
 
float mod_complexo(float x, float y)
 
</syntaxhighlight>
 
  
{{collapse top | Solução}}
 
<syntaxhighlight lang=c>
 
#include <stdio.h>
 
#include <math.h>
 
 
float mod_complexo(float x,float y)
 
{
 
  float modulo;/* Variaveis LOCAIS */
 
  modulo = sqrt( ((x*x) + (y*y)) ); // Funcao sqrt lembrar de utilizar math.h
 
  return modulo;
 
}
 
 
main()
 
{
 
  float num1, num2, result;/* Variaveis LOCAIS */
 
  printf("Entre com a parte real:\n");
 
  scanf("%f",&num1);
 
  printf("Entre com a parte imaginaria:\n");
 
  scanf("%f",&num2);
 
  result = mod_complexo(num1,num2);
 
  printf("Modulo do numero complexo: %f\n",result);
 
 
}
 
</syntaxhighlight>
 
{{collapse bottom}}
 
</li>
 
  
 
<li>
 
<li>
Linha 954: Linha 1 011:
 
</syntaxhighlight>
 
</syntaxhighlight>
 
</li>
 
</li>
 +
<li>
 +
Elaborar uma função que imprime uma mensagem:<br />
 +
'''ATENÇÃO: CUIDADO COM O CORONA!!!'''<br />
 +
Customize a função para que ela '''repita a mensagem N vezes''', onde N é passado como parâmetro. Será que é  importante que esta função retorne um valor?
 +
</li>
 +
 +
<li>
 +
Elaborar uma função "linha_vazada()" para desenhar uma linha da forma:<syntaxhighlight>
 +
XXbbbbbbbbbbbXX
 +
</syntaxhighlight>
 +
O caracter b apenas indica espaço em branco.
 +
Qual seria o tipo de retorno desta '''função'''?
 +
 +
Quais parâmetros ela tem?
 +
Propor uma versão customizada que proporcione receber como parâmetros a largura<br />
 +
total da linha (número de espaços em branco) mas mantendo sempre os lados com XX.
 +
 +
</li>
 +
 
</ol>
 
</ol>
  

Edição das 17h22min de 13 de setembro de 2022

Objetivos da Aula

  • Conceituar funções, parâmetros e valor de retorno;
  • Definir, declarar e chamar funções no C;
  • Declarar protótipo de funções;
  • Distinguir e saber criar variáveis locais e globais;
  • Aplicar funções para resolver subproblemas de um grande problema;
  • Noção de recursividade e o cuidado no uso...

Referências Históricas

Conceito de Função

Uma função é um "bloco de código" que resolve um dado problema
específico,  que possui um nome associado e 
que pode ser chamado quando necessário. Ao final da função a linha de execução
retorna para quem chamou a função. 
Exemplo: para calcular o seno de um ângulo chamamos uma função para resolver 
o problema específico: "calcular um seno". Dados de entrada devem ser fornecidos,
no caso o ângulo. O dado de saída é o seno computado deste ângulo.
Notar que a função permite REAPROVEITAR o código. Não precisamos a todo momento
reescrever um código que computa o seno. Basta chamar a função.

FUNÇÕES no C

Programa C: Um conjunto de funções

Um programa em C basicamente é um conjunto de funções. 
Uma função pode ser vista como um subprograma para o qual podemos repassar 
dados de entrada através de parâmetros e receber os resultados através 
do retorno da função.

Normalmente, um programa bem comportado em C possui pelo menos uma função: a função main(). Esta função é chamada no início da execução do programa. A primeira instrução da função main() é a primeira instrução executada pelo programa (pelo menos do ponto de vista do programador). Da mesma forma, a última instrução desta função é a última instrução a ser chamada.

Um programa normalmente vai apresentar um conjunto de funções. Por exemplo:

#include <stdio.h>

void func4()
{
    printf("Esta é a função func4()\n");
}

void func3()
{
    printf("Esta é a função func3()\n");
    func4();
}

void func2()
{
    printf("Esta é a função func2()\n");
}

void func1()
{
    printf("Esta é a função func1()\n");
    func2();
    func3();
}

int main()
{
    printf("Esta é a primeira instrução da função main()\n");
    func1();
    printf("Esta é a última instrução da função main()\n");
    return 0;
}

A sequência de chamada de funções pode ser ilustrada da forma:

FuncChamadaFuncoes.png

EXERCÍCIO: Compile e execute o programa acima. Verifique a ordem de impressão das mensagens e compare com as chamadas das funções.

NOTA: Uma função pode ser chamada várias vezes no programa. 
É O REAPROVEITAMENTO DE CÓDIGO...

Definição, declaração e chamada de Funções

NOTAR que existem 3 momentos diferentes de uso de funções:

  • Definição de função: é quando se constrói a função explicitando o seu nome, tipo de retorno, parâmetros e o seu corpo (instruções e variáveis locais;
  • Declaração da Função: é somente uma declaração contendo o nome da função, tipo de retorno e parâmetros. O corpo da função NÂO é explicitado pois supõe-se que ela foi definida em algum outro lugar;
  • Chamada (invocação) da Função: quando se usa a função, chamando-a pelo seu nome e passando os parâmetros (ATUAIS) que se deseja.

Por que usar Funções

  • Quebrar grandes problemas em pequenos problemas. Criar código para resolver cada pequeno problema e confiná-lo em funções:
    • uma função cujo objetivo é calcular o seno de um ângulo passado como parâmetro e retornar o seno calculado.
    • uma função que desenha um quadrado dado o tamanho do lado. Neste caso ela nem precisa retornar valor.
  • Facilita a divisão de tarefas em um grande projeto. O desenvolvedor X desenvolve a função seno, o desenvolvedor Y desenvolve a função coseno;
  • Facilita o teste de software: a função pode ser testada exaustivamente antes de ser disponibilizada para uso;
  • Deixa o código mais claro e mais otimizado: se eu quero computar o seno eu não preciso reproduzir o algoritmo que computa o seno, simplesmente chamo a função.

CONSELHO: SEMPRE que receber um problema a ser resolvido, tente quebrá-lo em subproblemas com "funcionalidades" bem definidas. Pense seriamente rm tratar cada subproblema como uma ou mais funções. Liste os possíveis parâmetros e o retorno destas funções. Agrupe as funções em módulos (serão arquivos fututamente).

Exemplo: Implementar uma função que imprimi uma linha com 10 caracteres X lado a lado. Na sequência, melhorar a função e imprimir 5 linhas com 10 caracteres Y cada.

Exercício: Implementar uma função que simula a jogada de dois dados e retorna a soma destes dois dados. Esta função poderia ser usada num jogo de adivinhação contra o computador.

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

/* definição da função soma de dados
   Sinopse: Esta função ....
   Parâmetros  de Entrada: não tem
   Saída: soma da jogada randômica de 2 dados
   Autor: ....
   Versão:
*/

int somar_dois_dados()
{
    int dado1, dado2, soma;

    dado1 =  rand() % 6 + 1;
    dado2 =  rand() % 6 + 1;
    soma = dado1 + dado2;
    return soma;
}

int main ()
{
      int teste;

      /* iniciar semente: */
      srand ( time(NULL) );

      teste = somar_dois_dados();
      printf("Valor da jogada de dados é %d\n", teste);
      return 0;
}

Exemplo de Funções com menus Multiníveis em modo texto

Considere uma aplicação que deve gerenciar salas e usuários de uma instituição. Ela deve permitir cadastrar salas e usuários para alguma finalidade. Teríamos que apresentar menus e submenus para esta facilidade. O código abaixo demonstra esta possibilidade. Note que o código somente apresenta os menus e o uso de funções para apresentar submenus e retornar ao menu principal. Ele não apresenta a lógica necessária para gerenciar usuários e salas.

Obs: Baseado nas discussões em cboard.cprogramming.com

Exemplo de menus e submenus usando funções para chamada de submenus
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

/* Autores: Professores PRG1 - IFSC -SJ   */
/******************************************/
/*
Para fins didáticos estão concentradas aqui
todas as funções para exemplificar a elaboração
de menus em modo texto.
Em versões finais o código deve ser organizado em arquivos .h
e .c, agrupando as funções conforme a funcionalidade.
Por exemplo: em um arquivo salas.c colocar as funções
de gerenciamento de sala, com os protótipos no salas.h
*/ 
/******************************************/

/******************************************/
/* Protótipos de funções  - colocar em .h */
/******************************************/

void gerenciar_usuarios();
void gerenciar_salas();
void adicionar_usuario();
void remover_usuario();
void adicionar_sala();
void remover_sala();

/******************************************/
/* Variáveis Globais                      */
/******************************************/

/* a fazer */

/******************************************/
int main()
{ 
   int opcao;

   do {
      system("clear");
      printf("**********************************\n");
      printf("Menu Nível 1\n\n");
      printf("1. Gererenciar Usuários\n");
      printf("2. Gerenciar Salas\n");
      printf("3. Sair\n");
      printf("**********************************\n");
      scanf("%d",&opcao);   
      switch (opcao) {
      case 1: gerenciar_usuarios();
              break;
      case 2: gerenciar_salas();
              break;
      case 3: printf("Finalizando Programa...\n"); 
              break;
      default: printf("Opção inexistente. Tente novamente...\n");
               sleep(1); /* tempo somente para fins de visualização */
               break;
      } 
  
   } while (opcao != 3);
}

/***************************************************/
/* Esta funções deveriam estar em arquivo separado */
/***************************************************/
void gerenciar_usuarios()
{
   int opcao;

   do {
      system("clear");
      printf("**********************************\n");
      printf("Menu Nível 2 - Gerenciar Usuários\n\n");
      printf("1. Adicionar Usuário\n");
      printf("2. Remover Usuário\n");
      printf("3. Sair do Gerenciar Usuários\n");
      printf("**********************************\n");
      scanf("%d",&opcao);   
      switch (opcao) {
      case 1: adicionar_usuario();
              break;
      case 2: remover_usuario();
              break;
      case 3: printf("Finalizando Gerenciar Usuários...\n"); 
              sleep(1); /* tempo somente para fins de visualização */
              break;
      default: printf("Opção inexistente. Tente novamente...\n");
               sleep(1); /* tempo somente para fins de visualização */
               break;
      } 
  
   } while (opcao != 3);
}

void adicionar_usuario()
{
  /* aqui poderia ter um menu nível 3 */
  printf("adicionando usuário\n ");
  sleep(1);
  printf("usuário adicionado\n ");
  sleep(1);
}

void remover_usuario()
{
  /* aqui poderia ter um menu nível 3 */
  printf("removendo usuário\n ");
  sleep(1);
  printf("usuário removido\n ");
  sleep(1);
}


/***************************************************/
/* Esta funções deveriam estar em arquivo separado */
/***************************************************/

void gerenciar_salas()
{
   int opcao;

   do {
      system("clear");
      printf("**********************************\n");
      printf("Menu Nível 2 - Gerenciar Salas\n\n");
      printf("1. Adicionar Sala\n");
      printf("2. Remover Sala\n");
      printf("3. Sair do Gerenciar Salas\n");
      printf("**********************************\n");
      scanf("%d",&opcao);   
      switch (opcao) {
      case 1: adicionar_sala();
              break;
      case 2: remover_sala();
              break;
      case 3: printf("Finalizando Gerenciar Sala...\n"); 
              sleep(1); /* tempo somente para fins de visualização */
              break;
      default: printf("Opção inexistente. Tente novamente...\n");
               sleep(1); /* tempo somente para fins de visualização */
               break;
      } 
  
   } while (opcao != 3);
}

void adicionar_sala()
{
  /* aqui poderia ter um menu nível 3 */
  printf("adicionando sala\n ");
  sleep(1);
  printf("sala adicionada\n ");
  sleep(1);
}

void remover_sala()
{
  /* aqui poderia ter um menu nível 3 */
  printf("removendo sala\n ");
  sleep(1);
  printf("sala removida\n ");
  sleep(1);
}

Passando parâmetros e recebendo valores de retorno

Uma função normalmente resolve um determinado problema para um determinado conjunto de dados e produz uma saída. Estes dados podem ser passados como parâmetros e a saída pode ser retornada pela função.

Exemplo: Uma função media_nums() que retorna a média de 3 números reais passados como parâmetros. Note que se trata de um exemplo pois NÃO seria necessário uma função para esta finalidade.

#include <stdio.h>

float media_nums(float num1, float num2, float num3)
{
  float media_local;

  media_local = (num1 + num2 + num3)/3;
  return media_local;
}

int main()
{
  float media, aux1, aux2, aux3;

  printf("\nEntre com numero 1: ");  
  scanf ("%f",&aux1);

  printf("\nEntre com numero 2: ");  
  scanf ("%f",&aux2);

  printf("\nEntre com numero 3: ");  
  scanf ("%f",&aux3);

  media = media_nums(aux1, aux2, aux3);
  printf ("\nmedia dos 3 numeros é %f\n", media);
  return 0;
}

ADS29002-PassagemParametrosC.png

Deve ser observado que:

  • após o nome da função, entre parênteses, são fornecidos os três parâmetros com os seus respectivos tipos. Os valores (conteúdos das variáveis) aux1, aux2 e aux3 são copiados para as variáveis num1, num2 e num3 da função media_nums().
  • a função media_nums() retorna um valor do tipo float (informado antes do nome da função) que é o valor da variável media_local. Este valor é copiado para a variável media da função main()
  • as variáveis num1, num2 e num3 bem como a variável media_local possuem escopo LOCAL, ou seja, são "vistas" somente pela função media_nums();
  • as variáveis media, aux1, aux2 e aux3 também possuem escopo LOCAL, ou seja são "vistas" somente pela função main();

NOTE que o formato de declaração de uma função é

 tipo_retorno nome_funcao( lista_de_parametros )
 {
   declaracao_variaveis_locais
   lista_instruções
   return; /* comando de retorno - pode ou não retornar valor - pode ser omitido */
 }

Por enquanto, assumiremos que variáveis devem ser somente declaradas no início da função (logo após a abertura do bloco com '{'. Existem situações que poderemos relaxar esta afirmação.

U ponto a ser observado é a questão do retorno de uma função. Se a função não retorna um valor então tipo de retorno deve ser void. Neste caso, para realizar o retorno no código deve ser usada a palavra reservada return.

Um pouco mais sobre parâmetros

O termo argumento ou parâmetro real (atual) é usado para referenciar os valores que estão sendo passados na CHAMADA da função. Os parâmetros formais referem-se aos parâmetros listados na função. É comum, no entanto, usar os termos argumentos e parâmetros como sinônimos e identificados pelo contexto em que estão sendo usados.

A passagem de parâmetros POR VALOR diz respeito a copiar o valor do argumento na CHAMADA da função para a variável associada ao parâmetro na função. Mais tarde falaremos na passagem de parâmetro POR REFERÊNCIA. Neste último é repassado o endereço da variável para a função. Por ora, usaremos a passagem POR VALOR.


Os parâmetros passados na CHAMADA de uma função não são necessariamente variáveis. Eles podem ser uma expressão qualquer (uma expressão SEMPRE resulta em um VALOR).

Exemplo de chamadas para a função media_nums():

#include <stdio.h>

/* OBS: num1, m2 e num3 são os parâmetros formais */
float media_nums(float num1, float num2, float num3)
{
  float media_local;

  media_local = (num1 + num2 + num3)/3;
  return media_local;
}

int main()
{
  float media, x,y,z;

  x = 5.7;
  y = 9.8;

  /* exemplo de chamada 1 */  
  media = media_nums(4.8,x,y*3);

  /* exemplo de chamada 2 */ 
  media = media_nums (x+y,y*y+5,(x+y)/2);
  return 0;
}

Deve ser observado que:

  • na chamada 1 do exemplo, os parâmetros são uma CONSTANTE, o valor de x, e o valor de y*3. Note que o compilador deve gerar código para resolver estas expressões antes de INVOCAR a função!.
  • na chamada 2 aparecem expressões ainda mais complexas. Todas elas devem ser resolvidas antes da função ser INVOCADA.

Funções Definidas pelo Usuário X Funções da Biblioteca

  • Existem funções que já foram implementadas e disponibilizadas através de uma biblioteca.
    • Exemplo: printf(), rand() etc;
    • Para usar corretamente estas funções devemos incluir a sua declaração no ínicio do programa (arquivo). Uma forma simples é incluir um arquivo cabeçalho contendo estas declarações (ex: #include <stdio.h>)
  • As funções implementadas pelo usuário são àquelas voltadas a aplicação específica que ele está trabalhando.
    • Exemplo: uma função para sortear a soma de dois dados. Toda vez que precisar de uma soma de dois dados lançados randomicamente, bastará chamar esta função.


EXERCÍCIO EM SALA: IMPLEMENTAR uma função para retornar a soma de N dados lançados randomicamente.

Perguntas a serem respondidas antes de começar a implementação:

  • Qual é a funcionalidade desta função? Qual o objetivo dela?
  • Esta função tem parâmetros?
  • A função retorna valor? De que tipo?
  • Liste possíveis variações desta função.

Variáveis GLOBAIS e variáveis LOCAIS

Se variáveis são declaradas dentro de uma função, então a visibilidade (ESCOPO) destas variáveis é LOCAL. Nenhuma outra função tem acesso a estas variáveis. Na realidade, o ESCOPO da variáivel LOCAL é o bloco (entre chaves) em que ela foi declarada.

Uma variável pode ser GLOBAL, ou seja, declarada FORA das funções. Neste caso a variável é VISTA por todas as funções.

Uma BOA PRÁTICA é evitar o uso de variáveis GLOBAIS para minimizar possibilidade de erros nos programas.

Seja o exemplo anterior modificado:

#include <stdio.h>

float media; /* Variável GLOBAL */

void media_nums(float num1, float num2, float num3)
{
  media = (num1 + num2 + num3)/3;
  return;
}

int main()
{
  float aux1, aux2, aux3; /* Variáveis LOCAIS */

  printf("\nEntre com numero 1: ");  
  scanf ("%f",&aux1);

  printf("\nEntre com numero 2: ");  
  scanf ("%f",&aux2);

  printf("\nEntre com numero 3: ");  
  scanf ("%f",&aux3);

  media_nums(aux1, aux2, aux3);
  printf ("\nmedia dos 3 numeros é %f\n", media);
  return 0;
}

Neste exemplo, a variável media é declarada como GLOBAL. Ela é MODIFICADA diretamente pela função media_nums() e impressa pela função main()

NOTE que como a função media_nums() não retorna valor então declaramos 
seu tipo de retorno como void que significa aqui NADA ou VAZIO. 
NOTE também que MESMO que a função retorne um valor, não é obrigatório colocá-la
no lado direito do sinal de atribuição.

OBSERVAR que uma função pode ser chamada dentro de qualquer expressão. Por exemplo, para o caso em que a função media_nums() retorna um valor, ela poderia ser usada como:

#include <stdio.h>

float media_nums(float num1, float num2, float num3)
{
  float media_local;

  media_local = (num1 + num2 + num3)/3;
  return media_local;
}

int main()
{
  float media, aux1, aux2, aux3;
  printf("\nEntre com numero 1: ");  
  scanf ("%f",&aux1);

  printf("\nEntre com numero 2: ");  
  scanf ("%f",&aux2);

  printf("\nEntre com numero 3: ");  
  scanf ("%f",&aux3);

  media = media_nums(aux1, aux2, aux3);
  printf ("\nmedia dos 3 numeros multiplicada por 10 é %f\n", 10*media_nums(aux1, aux2, aux3));
  return 0;
}

Um parênteses sobre nome de variáveis

  • Um nome de variável pode conter letras, dígitos e o underscore(sublinhado). Ela DEVE iniciar com um underscore ou uma letra.
  • Letras maúsculas e minúsculas podem ser usadas e são distinguidas (o C é CASE SENSITIVE)
  • Variáveis LOCAIS e GLOBAIS podem ter o mesmo nome. A variável LOCAL terá preferência no uso.

Exercício: Execute o programa abaixo e verifique as saídas.

#include <stdio.h>

int i=1;          /* GLOBAL  */

func()
{
    int i=100;     /* LOCAL */
    i=i+1;          /* incrementa LOCAL */
    printf( "Valor de i = %d na função func()\n", i );
}
   
main()
{
    i=i+1;          /* incrementa GLOBAL  */
    func();
    printf( "Valor de i = %d \n", i );
}


 NOTA: não é recomendado o uso de variáveis com o mesmo nome.

Iniciando variáveis na declaração

Tanto as variáveis LOCAIS como as GLOBAIS podem ser inicializadas na declaração.

Exemplo:

int alfa=1;

main()
{
  float beta=1.5;

  printf("Valor de alfa = %d e valor de beta = %f\n", alfa, beta);
}
 NOTA: variáveis LOCAIS não são iniciadas automaticamente com zero. Cabe ao programador iniciá-la corretamente.
 NOTA: variáveis GLOBAIS são iniciadas automaticamente com zero. 
       Mas mantenha-se informado sobre o sistema que está trabalhando...
       Em sistemas embarcados pode não ser verdade!

Exercícios

  1. Elaborar um programa contendo uma função da forma:
      float area_retang (float lado1 , float lado2)
    

    A função recebe os lados de um retângulo e retorna a área do mesmo. Crie uma VARIÁVEL LOCAL para armazenamento temporário da área.

    Solução
  2. Elaborar um programa contendo uma função da forma:
    float area_circ (float raio)
    

    A função recebe o raio de um círculo e retorna a área da mesma.


    Solução
  3. Elaborar um programa contendo uma função da forma: float dif_area_circ (float raio1, float raio2) A função recebe o raio de dois círculos e retorna a diferença da área entre eles. Reaproveitar o exercício anterior.
    Solução
  4. Faça uma função para calcular o módulo de um número complexo passado na forma retangular. O protótipo da função tem o seguinte aspecto:
    float mod_complexo(float x, float y)
    
    Solução
  5. Elaborar uma função que recebe uma temperatura em graus em Fahrenheit e retorna graus celsius.
  6. Elaborar uma função que calcula o índice massa corporal. Quais seriam os parâmetros da função?
  7. Elaborar uma função que recebe dois números inteiros. A função retorna a soma de todos os números entre eles (inclusive).
    Solução
    #include <stdio.h>
     
    /* a função calcula a soma de todos inteiros entre num1 e num2 inclusive */
    
    int soma_int(int num1, int num2)
    {
      int i, soma_acumulada = 0;
      if (num1>num2) {
         i=num2;
         num2=num1;
         num1=i;
      }      
      for (i=num1;i<=num2;i++) 
         soma_acumulada = soma_acumulada + i;
    
      return soma_acumulada;
    }
    
    int main()
    {
      int i,x,y, soma_acumulada;
    
      printf("Entre com o primeiro número da faixa \n");
      scanf ("%d", &x);
    
      printf("Entre com o segundo número da faixa \n");
      scanf ("%d", &y);
    
      soma_acumulada = soma_int(x,y);
      printf("soma acumulada entre %d e %d é %d\n", x,y,soma_acumulada);     
      return 0;
    }
    
  8. Elaborar um programa em C correspondente aos fluxogramas abaixo. Trata-se de um procedimento para calcular o fatorial de um número inteiro passado como parâmetro para uma função. A função fatorial é definida por: FluxogramaFatorial.jpg Neste fluxograma, o subprograma denominado CalcFatorial recebe um valor no parâmetro N (implicitamente inteiro) e retorna o valor calculado do fatorial. O fluxograma principal invoca duas vezes o subrograma. O retorno é armazenado nas variáveis NUM1 e NUM3. Quando um subprograma retorna um valor, ele é chamado de função. Para manter coerência com o C chamaremos qualquer subrprograma de função (independente de retornar valor).
    Solução
    #include <stdio.h>
     
    float calc_fatorial(int num)
    { 
      int i=1;
      float fat=1;/* Variaveis LOCAIS */
      while(i<=num){
      	fat = fat*i;
    	i++;
      }
      return fat;
    }
     
    int main()
    {
      float num1, num2, num3; /* Variáveis LOCAIS */
     
      num1 = calc_fatorial(5);
      num2 = 4;
      num3 = calc_fatorial(num2*3);
     
      printf ("num1: %f\n", num1);
      printf ("num2: %f\n", num2);
      printf ("num3: %f\n", num3);
      return 0;
    }
    
  9. Faça uma função para entrar com dois números inteiros pelo teclado e retornar a soma dos fatoriais destes números. Reutilize a função anterior.
    Solução
  10. Considere o exercício para desenho de uma figura retangular tal como repassado em aula aula anterior. Confine a solução do problema em uma função onde são repassados a margem, o número de colunas e o número de linhas a ser impresso. A função deve ter o seguinte protótipo: int desenhar_retang(int margem, int linha, coluna); Observe um exemplo de como poderia ser chamada esta função:
    include <stdio.h>
    int desenhar_retang(int margem, int linha, coluna)
    {
     /* implementar aqui */
    }
    
    
    main()
    {
      desenhar_retang(5,10,30);
    }
    
  11. Faça uma função para computar o número usando série da seguinte forma: . Observe que onde está infinito deve ser usado um parâmetro que permita limitar a computação a alguns termos. Esta função deve se UTILIZAR de uma outra função (a ser implementada) que faz a computação do fatorial de um número. Demonstre o funcionamento na função main(). O esqueleto da função é dado:
    float calc_e(int max_n)
    {
      // esta função deve chamar a função fatorial...
    }
    
  12. Faça uma função para computar a combinação simples de 'n' elementos agrupados 'p' a 'p' dada pela fórmula (extraído de Wikipedia:

    A função deve ter a estrutura do esqueleto abaixo e DEVE se utilizar de uma função que calcula o fatorial (fat()). O programa main deve testar o funcionamento da função, imprimindo a combinação de 4 elementos 2 a 2.
    int fat(int n)
    {
    }
    
    int combinacao (int n, int p)
    {
    
    }
    
    int main()
    {
     /* testar aqui */
    
      return 0;
    }
    
  13. Faça uma função para computar uma aproximação da função exponencial através dos N primeiros termos de: Wikipedia:

    Exemplo: Caso se deseje computar com N=5 teremos:
    que corresponde a somar os termos para n de 0 a 4:
    A função deve ter a estrutura do esqueleto abaixo e DEVE se utilizar de:
    uma função que calcula o fatorial (fat())
    uma função que computa a exponenciação (expon()).
    float expon(float x, int n)
    {
        /* implementar */
    }
    
    int fat(int n)
    {
        /* implementar */
    }
    float func_exp (int x, int N)
    {
        int n;
        float soma_ac = 0;
    
        /* esqueleto da solução */
        for(n = 0; n < N; n++)
            soma_ac = soma_ac + expon(x,n)/fat(n);
        /* retornar: a fazer */
    }
    
    int main()
    {
        /*  exemplo de uso*/
        float valor;
    
        /* calcula os 5 primeiros termos da série correspondente a e^4.3 */
        valor = func_exp(4.5,5);
    
    
        return 0;
    }
    
  14. Elaborar uma função que imprime uma mensagem:
    ATENÇÃO: CUIDADO COM O CORONA!!!
    Customize a função para que ela repita a mensagem N vezes, onde N é passado como parâmetro. Será que é importante que esta função retorne um valor?
  15. Elaborar uma função "linha_vazada()" para desenhar uma linha da forma:
     XXbbbbbbbbbbbXX

    O caracter b apenas indica espaço em branco. Qual seria o tipo de retorno desta função?

    Quais parâmetros ela tem? Propor uma versão customizada que proporcione receber como parâmetros a largura
    total da linha (número de espaços em branco) mas mantendo sempre os lados com XX.