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
(Criou página com '= AULA 8 - Funções no C =')
 
Linha 1: Linha 1:
= AULA 8 - Funções no C =
+
= FUNÇÕES no C =
 +
 
 +
===Objetivos===
 +
 
 +
O aluno deverá ser capaz de:
 +
 
 +
*dividir problemas em subproblemas e utilizar subrotinas para organizar a solução.
 +
*passar parâmetros em funções e retonar valores.
 +
 
 +
===Quebrando um problema em subproblemas: SUBPROGRAMAS===
 +
 
 +
PROBLEMA: Aprimorar o exemplo do controle de acesso para que, no caso de 3 tentativas de acesso seguidas, com senha errada, o sistema seja bloqueado.
 +
 
 +
*DADOS DE ENTRADA: SENHA /* variável que armazena a senha entrada pelo usuário ou administrador */
 +
*DADOS DE SAÍDA: mensagem de abertura da porta / usuário bloqueado*/
 +
*VARIÁVEIS INTERMEDIÁRIAS: CONT_ACESSO /* valor inicial zero - incrementada a cada senha inválida */
 +
 
 +
[[imagem:FluxogramaControleAcessoComContador.jpg|border|850px]]
 +
 
 +
Note que a variável CONT_ACESSO é iniciada com zero e
 +
incrementada a cada erro no fornecimento da senha. A
 +
atribuição CONT_ACESSO = CONT_+ACESSO + 1 deve ser
 +
interpretada da forma: acesse o valor de CONT_ACESSO e some 1
 +
a este valor. Coloque o resultado novamente em CONT_ACESSO
 +
(o conteúdo anterior é sobrescrito!)
 +
 
 +
Neste procedimento pode ser observado que:
 +
*começa a aparecer uma certa complexidade no fluxograma;
 +
*Além disto, não ficou uma abordagem muito interessante, pois se for o administrador que erra a senha, ele pode bloquear o usuário;
 +
*não existe forma de desbloquear a senha (zerar o contador), a não ser mudando a senha.
 +
 
 +
Em síntese, existem subproblemas adicionais a serem resolvidos. Como podemos resolvê-los sem deixar um fluxograma complexo?
 +
 
 +
Usaremos a caixa de processos pré-definidos que usaremos para invocar funções que resolvem determinado subproblema.
 +
 
 +
Inicialmente, vamos construir três subprogramas:
 +
* Iniciar_Sistema(): inicia variáveis do sistema, colocando o sistema em um estado inicial conhecido;
 +
* Tratar_Admin(): é o código que trata a funcionalidade associada ao administrador;
 +
* Tratar_User(): é a funcionalidade que trata o usuário (procedimento de abrir porta, bloquear etc).
 +
 
 +
 
 +
[[imagem:FluxogramaControleAcessoComSubprograma.jpg|850px]]
 +
 
 +
OBS: Note que foi usada uma variável auxiliar AUX que permite ajustar o valor
 +
de número de acessos a ser mostrado no display. Note também que na caixa DISPLAY foi usado
 +
uma string a ser impressa e a variável AUX cujo conteúdo deve ser impresso. Ambos separados
 +
por vírgula.
 +
 
 +
===PARÂMETROS E RETORNO DE VALORES EM SUBPROGRAMAS===
 +
 
 +
Para tornar ainda mais interessante o uso de subprogramas, vamos ver o conceito de passagem de parâmetros e retorno de valores.
 +
 
 +
Quando chamamos (invocamos) um subprograma podemos passar valores (dados de entrada) para este subprograma.
 +
Estes valores são passados através de variáveis especiais que chamamos de parâmetros.
 +
 
 +
Parâmetros podem ser passados por valor e por referência. Por valor é quando os dados a serem passados na invocação
 +
do subprograma são copiados para uma variável do subprograma.
 +
 
 +
Os parâmetros são passados por referência quando o que é passado para o subprograma é simplesmente o endereço da variável
 +
repassada na invocação do subprograma.
 +
 
 +
Não existe uma forma explícita de definir os parâmetros em um fluxograma. Deve-se realizar um comentário antes ou ao lado do mesmo especificando o tipo e como será tratado o parâmetro.
 +
 
 +
EXEMPLO: Seja elaborar um fluxograma correspondente a uma subprograma que deve calcular o fatorial de um número inteiro passado como parâmetro. O subprograma deve retornar o valor calculado.
 +
 
 +
A função fatorial é definida por:
 +
 
 +
:<math>n!=\prod_{k=1}^n k\qquad\forall n\in\mathbb{N}</math>
 +
 
 +
 
 +
[[imagem:FluxogramaFatorial.jpg|border|650px]]
 +
 
 +
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).
 +
 
 +
 
 +
===Exemplo de Função usando pseudo-código===
 +
 
 +
Seja uma função que retorna a média de 5 números reais passados como parâmetros:
 +
 
 +
<code>
 +
real FUNCAO(real num1, real num2, real num3, real num 4, real num5)
 +
  VARIAVEIS
 +
      media: real
 +
  INICIO
 +
    media = (num1+num2+num3+num4+num5) /5
 +
    RETORNAR media
 +
  FIM
 +
</syntaxhighlight>
 +
 
 +
===EXERCÍCIOS===
 +
 
 +
''EXERCÍCIO 1'': Implementar uma função (subprograma), usando fluxograma, que recebe dois números inteiros como parâmetro. A função retorna 1 se os números forem iguais, 0 se o primeiro número maior que o segundo e -1 se o segundo for maior que o primeiro.
 +
Mostre um exemplo de uso a partir de um fluxograma principal.
 +
 
 +
''EXERCÍCIO 2'': Usando a formula de Heron, implemente na forma de pseudo-código uma função que recebe três números reais (lados de um triângulo) e retorne o valor da área do mesmo.
 +
 
 +
''EXERCÍCIO 3'': Implementar uma função (subprograma), usando fluxograma, para computar o valor da PG, dados como parâmetros ''s'' e ''q'', onde "s" é o número inicial e  "q" a razão da progressão. A função deve retornar um número real que é o valor da PG.
 +
 
 +
Obs: Para PG tem-se:
 +
 
 +
:<math> a_1 = s </math>
 +
:<math> a_n = q\times a_{n-1} </math> ou
 +
:<math>a_n=a_1.q^{n-1}\,\!</math>
 +
 
 +
''EXERCÍCIO 4:'' Modificar o sistema de controle de acesso para incluir a inserção de nome de usuário (USERID) e senha (SENHA). Prever a existência de dois usuários (USERID_1, USERID_2, SENHA_1, SENHA_2). O admin poderá ser identificado pelo nome ADMIN. Prever bloqueio por usuário (duas variáveis contadores).
 +
Sugestão: criar funcões separadas para tratamento de cada usuário. Em breve veremos como podemos contornar esta duplicação através da parametrização de funções/subprogramas.
 +
 
 +
===Funções no C ===
 +
 
 +
====Chamando 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:
 +
<syntaxhighlight lang=c >
 +
#include <stdio.h>
 +
 
 +
func4()
 +
{
 +
    printf("Esta é a função func4()\n");
 +
}
 +
 
 +
func3()
 +
{
 +
    printf("Esta é a função func3()\n");
 +
    func4();
 +
}
 +
 
 +
func2()
 +
{
 +
    printf("Esta é a função func2()\n");
 +
}
 +
 
 +
func1()
 +
{
 +
    printf("Esta é a função func1()\n");
 +
    func2();
 +
    func3();
 +
}
 +
 
 +
main()
 +
{
 +
    printf("Esta é a primeira instrução da função main()\n");
 +
    func1();
 +
    printf("Esta é a última instrução da função main()\n");
 +
}
 +
</syntaxhighlight>
 +
 
 +
A sequência de chamada de funções pode ser ilustrada da forma:
 +
 
 +
[[imagem:FuncChamadaFuncoes.png|600px]]
 +
 
 +
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...
 +
 
 +
====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
 +
 
 +
<syntaxhighlight lang=c>
 +
#include <stdio.h>
 +
 
 +
float media_nums(float num1, float num2, float num3)
 +
{
 +
  float media_local;
 +
 
 +
  media_local = (num1 + num2 + num3)/3;
 +
  return media_local;
 +
}
 +
 
 +
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);
 +
}
 +
 
 +
</syntaxhighlight>
 +
 
 +
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
 +
 +
    instruções
 +
  }
 +
 
 +
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.
 +
 
 +
====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. 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()'':
 +
 
 +
<syntaxhighlight lang=c>
 +
 
 +
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);
 +
}
 +
</syntaxhighlight>
 +
 
 +
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.
 +
 
 +
===Variáveis GLOBAIS e variáveis LOCAIS ===
 +
 
 +
Se variáveis são declaradas dentro de uma função, então a visbilidade (ESCOPO) destas variáveis é LOCAL. Nenhuma outra função tem acesso a estas variáveis.
 +
 
 +
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:
 +
 
 +
<syntaxhighlight lang=c>
 +
#include <stdio.h>
 +
 
 +
float media; /* Variável GLOBAL */
 +
 
 +
void media_nums(float num1, float num2, float num3)
 +
{
 +
  media = (num1 + num2 + num3)/3;
 +
  return;
 +
}
 +
 
 +
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);
 +
}
 +
 
 +
</syntaxhighlight>
 +
 
 +
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.
 +
 
 +
Na realidade, 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:
 +
 
 +
<syntaxhighlight lang=c>
 +
#include <stdio.h>
 +
 
 +
float media_nums(float num1, float num2, float num3)
 +
{
 +
  float media_local;
 +
 
 +
  media_local = (num1 + num2 + num3)/3;
 +
  return media_local;
 +
}
 +
 
 +
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));
 +
}
 +
</syntaxhighlight>
 +
 
 +
==== 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.
 +
 
 +
<syntaxhighlight lang=c>
 +
#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 );
 +
}
 +
</syntaxhighlight>
 +
 
 +
 
 +
  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:
 +
 
 +
<syntaxhighlight lang=c>
 +
 
 +
int alfa=1;
 +
 
 +
main()
 +
{
 +
  float beta=1.5;
 +
 
 +
  printf("Valor de alfa = %d e valor de beta = %f\n", alfa, beta);
 +
}
 +
</syntaxhighlight>
 +
 
 +
  NOTA: variáveis LOCAIS não são iniciadas automaticamente: 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!
 +
 
 +
====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. 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()'':
 +
 
 +
<syntaxhighlight lang=c>
 +
 
 +
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);
 +
}
 +
</syntaxhighlight>
 +
 
 +
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.

Edição das 22h52min de 26 de agosto de 2014

FUNÇÕES no C

Objetivos

O aluno deverá ser capaz de:

  • dividir problemas em subproblemas e utilizar subrotinas para organizar a solução.
  • passar parâmetros em funções e retonar valores.

Quebrando um problema em subproblemas: SUBPROGRAMAS

PROBLEMA: Aprimorar o exemplo do controle de acesso para que, no caso de 3 tentativas de acesso seguidas, com senha errada, o sistema seja bloqueado.

  • DADOS DE ENTRADA: SENHA /* variável que armazena a senha entrada pelo usuário ou administrador */
  • DADOS DE SAÍDA: mensagem de abertura da porta / usuário bloqueado*/
  • VARIÁVEIS INTERMEDIÁRIAS: CONT_ACESSO /* valor inicial zero - incrementada a cada senha inválida */

FluxogramaControleAcessoComContador.jpg

Note que a variável CONT_ACESSO é iniciada com zero e
incrementada a cada erro no fornecimento da senha. A 
atribuição CONT_ACESSO = CONT_+ACESSO + 1 deve ser 
interpretada da forma: acesse o valor de CONT_ACESSO e some 1
a este valor. Coloque o resultado novamente em CONT_ACESSO
(o conteúdo anterior é sobrescrito!)

Neste procedimento pode ser observado que:

  • começa a aparecer uma certa complexidade no fluxograma;
  • Além disto, não ficou uma abordagem muito interessante, pois se for o administrador que erra a senha, ele pode bloquear o usuário;
  • não existe forma de desbloquear a senha (zerar o contador), a não ser mudando a senha.

Em síntese, existem subproblemas adicionais a serem resolvidos. Como podemos resolvê-los sem deixar um fluxograma complexo?

Usaremos a caixa de processos pré-definidos que usaremos para invocar funções que resolvem determinado subproblema.

Inicialmente, vamos construir três subprogramas:

  • Iniciar_Sistema(): inicia variáveis do sistema, colocando o sistema em um estado inicial conhecido;
  • Tratar_Admin(): é o código que trata a funcionalidade associada ao administrador;
  • Tratar_User(): é a funcionalidade que trata o usuário (procedimento de abrir porta, bloquear etc).


FluxogramaControleAcessoComSubprograma.jpg

OBS: Note que foi usada uma variável auxiliar AUX que permite ajustar o valor
de número de acessos a ser mostrado no display. Note também que na caixa DISPLAY foi usado
uma string a ser impressa e a variável AUX cujo conteúdo deve ser impresso. Ambos separados
por vírgula.

PARÂMETROS E RETORNO DE VALORES EM SUBPROGRAMAS

Para tornar ainda mais interessante o uso de subprogramas, vamos ver o conceito de passagem de parâmetros e retorno de valores.

Quando chamamos (invocamos) um subprograma podemos passar valores (dados de entrada) para este subprograma.
Estes valores são passados através de variáveis especiais que chamamos de parâmetros.
Parâmetros podem ser passados por valor e por referência. Por valor é quando os dados a serem passados na invocação
do subprograma são copiados para uma variável do subprograma.
Os parâmetros são passados por referência quando o que é passado para o subprograma é simplesmente o endereço da variável
repassada na invocação do subprograma.

Não existe uma forma explícita de definir os parâmetros em um fluxograma. Deve-se realizar um comentário antes ou ao lado do mesmo especificando o tipo e como será tratado o parâmetro.

EXEMPLO: Seja elaborar um fluxograma correspondente a uma subprograma que deve calcular o fatorial de um número inteiro passado como parâmetro. O subprograma deve retornar o valor calculado.

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).


Exemplo de Função usando pseudo-código

Seja uma função que retorna a média de 5 números reais passados como parâmetros:

real FUNCAO(real num1, real num2, real num3, real num 4, real num5)

 VARIAVEIS
      media: real
 INICIO
    media = (num1+num2+num3+num4+num5) /5
    RETORNAR media 
 FIM

</syntaxhighlight>

EXERCÍCIOS

EXERCÍCIO 1: Implementar uma função (subprograma), usando fluxograma, que recebe dois números inteiros como parâmetro. A função retorna 1 se os números forem iguais, 0 se o primeiro número maior que o segundo e -1 se o segundo for maior que o primeiro. Mostre um exemplo de uso a partir de um fluxograma principal.

EXERCÍCIO 2: Usando a formula de Heron, implemente na forma de pseudo-código uma função que recebe três números reais (lados de um triângulo) e retorne o valor da área do mesmo.

EXERCÍCIO 3: Implementar uma função (subprograma), usando fluxograma, para computar o valor da PG, dados como parâmetros s e q, onde "s" é o número inicial e "q" a razão da progressão. A função deve retornar um número real que é o valor da PG.

Obs: Para PG tem-se:

ou

EXERCÍCIO 4: Modificar o sistema de controle de acesso para incluir a inserção de nome de usuário (USERID) e senha (SENHA). Prever a existência de dois usuários (USERID_1, USERID_2, SENHA_1, SENHA_2). O admin poderá ser identificado pelo nome ADMIN. Prever bloqueio por usuário (duas variáveis contadores). Sugestão: criar funcões separadas para tratamento de cada usuário. Em breve veremos como podemos contornar esta duplicação através da parametrização de funções/subprogramas.

Funções no C

Chamando 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>

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

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

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

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

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

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...

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

#include <stdio.h>

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

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

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);
}

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

   instruções
 }

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.

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. 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():

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);
}

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.

Variáveis GLOBAIS e variáveis LOCAIS

Se variáveis são declaradas dentro de uma função, então a visbilidade (ESCOPO) destas variáveis é LOCAL. Nenhuma outra função tem acesso a estas variáveis.

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:

#include <stdio.h>

float media; /* Variável GLOBAL */

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

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);
}

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.

Na realidade, 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;
}

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));
}

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: 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!

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. 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():

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);
}

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.