Search buenodc

Nesta página
  1. 1. O que é uma função? Definição e chamada
  2. 2. Parâmetros
  3. 3. Funções com e sem retorno

Funções

Imagine um programa que precisa calcular o preço com desconto de vários produtos, um de cada vez, sempre com a mesma fórmula. Sem uma forma de nomear esse cálculo, você acaba copiando e colando o mesmo trecho de código várias vezes ao longo do programa, e se um dia a fórmula mudar, precisa lembrar de atualizar cada cópia espalhada. Esta semana resolve esse problema: você aprende a organizar um programa em funções, blocos de código com nome que podem ser reaproveitados de qualquer ponto do programa, e aprofunda os parâmetros e os valores de retorno.

Base bibliográfica: este material segue a seção 3.2 (Funções Definidas pelo Programador) de SAVITCH, C++ Absoluto (Pearson Addison Wesley, 2004).

1. O que é uma função? Definição e chamada

Uma função é um bloco de código que recebe um nome, e pode ser chamado de qualquer ponto do programa, quantas vezes for preciso, sem repetir o código em si. Em vez de copiar e colar uma fórmula toda vez que ela é necessária, você escreve ela uma única vez, dentro de uma função, e daí em diante só precisa chamar essa função pelo nome.

Uma boa forma de guardar essa ideia é pensar numa receita de bolo: você escreve o passo a passo uma única vez, e pode seguir essa receita quantas vezes quiser, sempre que quiser fazer aquele bolo de novo. Os ingredientes são como as informações que você pode dar pra função usar, e o bolo pronto é o valor que ela devolve no final.

E aqui vai uma boa notícia: você já vem escrevendo funções desde a Semana 2, sem perceber. Toda vez que um programa em C++ roda, uma função chamada main é chamada automaticamente pelo sistema operacional, e main nada mais é do que uma função, com um nome especial e reservado.

Anatomia de uma função

void mensagemBoasVindas() {
    cout << "Bem-vindo ao sistema!" << endl;
}

Toda função tem duas partes. O cabeçalho, na primeira linha, com o tipo do valor retornado (aqui, void, ou seja, nenhum valor) e o nome da função. E o corpo, entre chaves, com os comandos que ela executa. Juntos, cabeçalho e corpo formam a definição completa da função.

Para chamar uma função, basta usar o nome dela, seguido de parênteses, no meio de um programa:

mensagemBoasVindas();

Mesmo uma função que não recebe nenhuma informação extra precisa dos parênteses vazios, tanto na definição quanto na chamada.

Uma função com parâmetro

Uma função também pode receber uma informação de fora, chamada parâmetro, para usar dentro do corpo:

double celsiusParaFahrenheit(double celsius) {
    return celsius * 9.0 / 5.0 + 32;
}

Aqui, celsius é um parâmetro: o tipo dele (double) e o nome que ele vai ter dentro da função aparecem entre os parênteses do cabeçalho. A função usa esse valor no cálculo, e devolve o resultado com return.

Nesta disciplina, a função sempre aparece inteira, antes do main. O compilador lê o programa de cima para baixo, uma linha de cada vez: por isso, quando ele chega numa chamada dentro do main, precisa já ter lido a função inteira antes, para saber o que ela devolve e o que ela espera receber.

🎥 Vídeo 1 de 3: O que são funções? Definição e chamada (~6 min)

2. Parâmetros

Uma função pode ter quantos parâmetros forem necessários, cada um com seu próprio tipo, separados por vírgula:

double calcularPrecoComDesconto(double preco, double percentualDesconto) {
    return preco - (preco * percentualDesconto / 100);
}

Na chamada, os valores são passados na mesma ordem em que os parâmetros foram declarados:

cout << calcularPrecoComDesconto(100.0, 10.0) << endl;

O primeiro valor, 100.0, vai para preco; o segundo, 10.0, vai para percentualDesconto. Não é o nome do parâmetro que decide quem recebe o quê: é a posição.

O mesmo padrão vale para três parâmetros, ou mais:

double calcularTotalComDesconto(double preco, int quantidade, double percentualDesconto) {
    double total = preco * quantidade;
    return total - (total * percentualDesconto / 100);
}

A ordem dos parâmetros importa

calcularPrecoComDesconto(10.0, 100.0);

Se você inverter a ordem dos valores na chamada, o C++ não percebe o erro: ele só conecta os valores aos parâmetros pela posição em que aparecem, nunca pelo nome que você tinha em mente. Aqui, preco receberia 10, e percentualDesconto receberia 100: um desconto de cem por cento sobre um produto de dez reais, um resultado sem sentido, mas sem nenhum erro de compilação. Quanto mais parâmetros uma função tem, mais fácil é errar a ordem: vale a pena sempre conferir a ordem declarada na definição antes de escrever a chamada.

Parâmetro versus argumento

Dois termos que costumam se confundir. Parâmetro é o nome usado dentro da definição da função, como preco e percentualDesconto: ele existe só ali dentro, guardando o lugar de um valor que ainda vai chegar. Argumento é o valor real passado na chamada, como 100.0 e 10.0. O parâmetro é o espaço reservado; o argumento é o que realmente preenche esse espaço, a cada chamada.

🎥 Vídeo 2 de 3: Parâmetros (~5 min)

3. Funções com e sem retorno

Toda função em C++ pertence a uma de duas famílias. As que devolvem um valor têm um tipo de retorno diferente de void, e sempre terminam executando um return seguido de uma expressão. As que não devolvem nada usam void como tipo de retorno, e não precisam de um return no final: a função simplesmente termina quando chega na última linha do corpo.

Return numa função void

Uma função void também pode ter um comando return, mas sem nenhuma expressão depois: só a palavra return, seguida de ponto e vírgula. Ele não devolve valor nenhum: só encerra a execução da função ali mesmo, antes do final do corpo. É útil para sair mais cedo de uma função, quando alguma condição já resolveu o que precisava ser feito.

void mostrarPrecoComDesconto(double preco, double percentualDesconto) {
    if (percentualDesconto < 0 || percentualDesconto > 100) {
        cout << "Desconto invalido" << endl;
        return;
    }
    double precoFinal = preco - (preco * percentualDesconto / 100);
    cout << "Preco final: " << precoFinal << endl;
}

Se o percentual de desconto for inválido, a função mostra uma mensagem de erro e usa return, sozinho, para encerrar ali mesmo, sem calcular nada. Se o percentual for válido, esse if nunca executa, e a função segue até o final, calculando e mostrando o preço normalmente.

Esquecer o return

double calcularMedia(double n1, double n2) {
    double media = (n1 + n2) / 2;
}

Diferente de uma função void, uma função que devolve um valor precisa, obrigatoriamente, executar um return com uma expressão, em todo caminho possível dentro dela. Aqui falta esse return: o compilador costuma avisar, mas em muitos casos deixa compilar assim mesmo, e o valor devolvido vira lixo de memória, imprevisível.

Voltando à receita de bolo: uma função que devolve um valor é como uma receita que sempre termina com um prato pronto na mesa. Uma função void é mais como uma tarefa da cozinha que não produz um prato por si só, tipo lavar a louça: você faz a ação, mas não há nada para servir no final.

🎥 Vídeo 3 de 3: Funções com e sem retorno (~5 min)

Leitura da Semana 7 - Base: Savitch, C++ Absoluto, seção 3.2. Faça a lista de exercícios e traga suas dúvidas para o encontro síncrono.