Programação C/C++
Prof. Márcio Sarroglia Pinho

Subalgoritmos (Funções)


Definição   Porque usar as funções ? Primeiro Exemplo  Formato Geral 
Parâmetros Localização das Funções no Programa-fonte Verificação dos tipos dos parâmetros Escopo de Variáveis
Funções e Procedimentos Passagem de Parâmetros por Referência
Passagem de Vetores por Parâmetros


Definição
    Conjunto de comandos agrupados em um bloco, que recebe um nome e através deste pode ser evocado.


Porque usar funções ?


Primero Exemplo

        Em primeiro lugar, imaginemos que você necessite várias vezes em seu programa imprimir a mensagem "Pressione a tecla ENTER" e esperar que o usuário tecle ENTER, caso o usuário tecle algo diferente o programa deve imitir um BEEP.

        Você pode fazer um laço de WHILE sempre que isto fosse necessário.

        Uma alternativa é criar uma função. Com o uso de funções, este processo de repetição fica simplificado. Observe o exemplo a seguir.


#include <stdio.h>

void EsperaEnter()  // Definição da função
"EsperaEnter"
{
    int tecla;
    printf("Pressione ENTER\n");
    do
    {
        tecla = getchar();
        if (tecla !=13) // Se nao for ENTER
        {
            printf("Digite ENTER\n");
        }
    } while(tecla != 13); // 13 e' o codigo ASCII do ENTER
}

void main()  
{
    EsperaEnter();      // Chamada da função definida antes
    // ...........
    EsperaEnter();      // Chamada da função definida antes
    // ...........
    EsperaEnter();      // Chamada da função definida antes 
}


Formato Geral de uma Função em C

tipo_da_funcao  NomeDaFuncao (Lista_de_Parametros)
{
// corpo da função
}

    A Lista_de_Parametros, também é chamada de Lista_de_Argumentos, é opcional.


Parâmetros

        A fim de tornar mais amplo o uso de uma função, a linguagem C permite o uso de parâmetros. Este parâmetros possibilitam que se definida sobre quais dados a função deve operar. A função sound(freq), por exemplo, recebe como parâmetro a freqüência do som a ser gerado, permitindo que se defina seu comportamento a partir deste valor.

        Para definir os parâmetros de uma função o programador deve explicitá-los como se estive declarando uma variável, entre os parênteses do cabeçalho da função. Caso precise declarar mais de um parâmetro, basta separá-los por vírgulas. No exemplo a seguir temos a função SOMA que possui dois parâmetros, sendo o primeiro um float e o segundo um int.

void SOMA(float a, int b)  // basta separar por vírgulas
{
   float result;     // a declaração de variáveis é igual ao que

                     // se faz na função main
   result = a+b;
   printf("A soma de %6.3f com %d é %6.3f\n, a,b,Result);
}

        Os parâmetros da função na sua declaração são chamados parâmetros formais. Na chamada da função os parâmetros são chamados parâmetros atuais/reais.

        Os parâmetros são passados para uma função de acordo com a sua posição. Ou seja, o primeiro parâmetro atual(da chamada) define o valor o primeiro parâmetro formal (na definição da função, o segundo parâmetro atual define o valor do segundo parâmetro formal e assim por diante. Os nomes dos parâmetros na chamada não tem relação com os nomes dos parâmetros na definição da função.

        No código a seguir, por exemplo, a função SOMA é chamada recebendo como parâmetros as variáveis "b" e "a", nesta ordem.

#include <stdio.h>

void SOMA(float a, int b)  // basta separar os parâmetros por vírgulas
{
   float result;     // a declaração de variáveis é igual ao que

                     // se faz na função main
   result = a+b;
   printf("A soma de %6.3f com %d é %6.3f\n, a,b,Result);
}

int main()
{
    int a;
    float b;

    a = 10;
    b = 12.3;
    SOMA(b,a);  // Chamada da função SOMA(12.3,10);

    return 0;
}

        O resultado do programa é a impressão da seguinte mensagem: A soma de 12.300 com 10 é 22.300


Localização das Funções no Fonte

        A princípio podemos tomar com regra a seguinte afirmativa toda função deve ser declarada antes de ser usada

        A declaração de uma função em linguagem C não é exatamente o que fizemos até  agora. O que estamos fazendo é a  definição da função antes de seu uso. Na definição da função está implícita a declaração.

        Alguns programadores preferem que o início do programa seja a primeira parte de seu programa. Para isto a linguagem C permite que se declare uma função, antes de defini-la. Esta declaração é feita através do protótipo da função. O protótipo da função nada mais é do que  o trecho de código que especifica o nome e os parâmetros da função.

        No exemplo a seguir a função  SOMA é prototipada antes de ser usada e assim pôde ser chamada antes de ser definida.

#include <stdio.h>

void SOMA(float a, int b);  // Protótipo da função SOMA

void main()
{
    SOMA(16.7,15);  // Chamada da função SOMA antes de sua definição,
}                    // mas após sua prototipação

int  SOMA(float a, int b)  // Definição da função SOMA
{
   float result;     // a declaração de variáveis é igual ao que

                     // se faz na função main
   result = a+b;
   printf("A soma de %f com %d é %6.3f\n, a,b,result);
   return 0;
}

Atenção: existem  compiladores mais simplificados ou antigos que não obrigam a declaração da funçãoantes de seu uso !!! Muito cuidado com eles !! Veja no item a seguir.


Verificação dos Tipos dos Parâmetros

        A princípio, dados usados parâmetros atuais(aqueles da chamada da função) devem ser dos mesmos tipos dos parâmetros formais. Se isto não ocorrer, mas a declaração da função vier antes de seu uso, os compiladores C modernos se encarregam de converter automaticamente os tipos como se estivesemos usando um CAST.

        Entretanto, tenha muito cuidado se as três condições a seguir se verificarem:

        Se as três condições se verificarem o resultado da execução da função é ímprevisível !

        No caso de você declarar corretamente a função antes de usá-la, a conversão de tipos é feita como no caso de variáveis. No exemplo a seguir a função SOMA é chamada com os parâmetros reais dos tipos int e float, nesta ordem. Como na declaração da função o primeiro parâmetro é float e o segundo é int,  é feita uma conversão de int para float no caso do   primeiro parâmetro e de float para int no caso do segundo parâmetro.

#include <stdio.h>

void SOMA(float a, int b);  // Protótipo da função SOMA

void main()
{
   float f;

    f = 20.7;
    SOMA(16,f);  
}                

        Neste exemplo o primeiro parâmetro é convertido para 16.0 e o segundo para 20.   O que ocorre, de fato, é que a chamada da função é feita como se mesma fosse substituída por:

SOMA((float)16,(int)f);  


Escopo de Variáveis

        Por escopo de uma variável entende-se o bloco de código onde esta variável é válida. Com base nisto, temos as seguintes afirmações:

        No trecho de código a seguir tem-se um exemplo com funções e variáveis com nomes iguais.

#include <stdio.h>
void FUNC1()
{
int B;
   B = -100;
printf("Valor de B dentro da função FUNC1: %d\n", B);
}
void FUNC2()
{
int B;
   B = -200;
printf("Valor de B dentro da função FUNC2: %d\n", B);
} void main()
{
int B;
  
B = 10;
printf("Valor de B: %d\n", B);
B = 20;
FUNC1();
printf("Valor de B: %d\n", B);
B = 30;
FUNC2();
printf("Valor de B: %d\n", B);
getch();
}

SAÍDA

Valor de B: 10
Valor de B dentro da função FUNC1: -100
Valor de B: 20
Valor de B dentro da função FUNC2: -200
Valor de B: 30


Sugere-se, antes da leitura das próximas seções, a consulta à página sobre ponteiros.


Passagem de Parâmetros por referência

A passagem de parâmetros apresentada a até aqui é chamada de passagem por valor. Nesta modalidade, a chamada da função passa o valor do parâmetro para a função. Desta forma, alterações do parâmetro dentro da função não afetarão a variável usada na chamada da função.

No exemplo a seguir a variável f, passada por parâmetro para a função Zera não será alterado dentro da função.

#include <stdio.h>

void Zera(float a)
{
    a = 0;
}

void main()
{
   float f;

    f = 20.7;
    Zera(f);
    printf("%d", f); // o valor impresso será 20.7 pois o parâmetro da função foi passado por valor.

}

Para permitir a alteração da variável usada como parâmetro é preciso passar o endereço da variável, caracterizando desta forma uma passagem por referência.

Para passar o endereço de uma variável para uma função, deve-se tomar as seguintes providências:
- na chamada da função deve-se usar o operador & antes do nome da variável;
- no cabeçalho da função,
declarar o parâmetro como um ponteiro;
- dentro da função, deve-se usar o operado de derreferência * para alterar o conteúdo da variável.

O exemplo a seguir apresenta uma nova versão da função Zera, desta feita com o uso de um parâmetro passado por referência.

#include <stdio.h>

void Zera(float *a) // Define que o parâmetro é uma referência à outra variável
{
    *a = 0; // utiliza o operador de derreferência para alterar o conteúdo da variável
}

void main()
{
   float f;

    f = 20.7;
    Zera(&f);  // Passa o endereço da variável f para a função
    printf("%d", f); // o valor impresso será 0.0 pois o parâmetro da função foi passado por referência.

}



Passagem de Vetores por Parâmetros

A passagem de vetores por parâmetro é sempre por referência. Isto significa que não se deve, na chamada da função, passar o endereço do vetor. Isto ocorre pois, por convenção, o nome do vetor já representa o endereço inicial deste vetor namemória.
No cabeçalho da função que recebe um vetor, há duas formas de definir o parâmetro que é um vetor. Na primeira declara-se o vetor como se faz normalmente na linguagem. O exemplo a seguir mostra o uso desta abordagem.


void ZeraVet(float V[10], int qtd)
{
    int i;
    for(i=0;i<qtd;i++)
       V[i] = 0.0;
}

void main()
{
    int i;
    float Vet[10];

    ZeraVet(Vet,10);  // Passa o nome do vetor como parâmetro
   
for(i=0;i<10;i++)
       printf("%d ", Vet[i]); // todos os elementos terão valor 0.0

}

Na segunda abordagem, pode-se declarar o parâmetro como um ponteiro para o tipo de dado que forma o vetor. No caso do exemplo a seguir, como o vetro foi declarado com um vetor de float, o parâmetro da função deve ser float *v.
No código da função, o acesso aos dados do vetor é feito da mesma maneira que é feito quando se declara o vetor explicitamente.

void ZeraVet2(float *V, int qtd)
{
    int i;
    for(i=0;i<qtd;i++)
       V[i] = 0;
}

void main()
{
    int i;
    float Vet[10];

    ZeraVet(Vet,10); 
// Passa o nome do vetor como parâmetro
   
for(i=0;i<10;i++)
       printf("%d ", Vet[i]);
// todos os elementos terão valor 0.0
}