Funções em C
LidoNesta aula, você aprenderá a criar e usar funções em C, desde a declaração e definição até o uso de protótipos, parâmetros e retorno. Também exploraremos o tipo void e suas aplicações, com exemplos práticos e exercícios para fixar o conteúdo.
Funções são blocos de código reutilizáveis que executam uma tarefa específica. Elas permitem organizar o programa em partes menores, facilitando a leitura, manutenção e teste do código. Em C, toda função tem um tipo de retorno, um nome, uma lista de parâmetros (que pode ser vazia) e um corpo com as instruções. Nesta aula, vamos explorar os conceitos fundamentais de declaração, definição, protótipos, parâmetros, retorno e o tipo void.
Dominar funções é essencial para escrever programas modulares e eficientes. Você verá como declarar funções corretamente, como passar dados para elas e como receber resultados de volta, além de entender quando usar void tanto no retorno quanto nos parâmetros.
Declaração e definição
Em C, uma função precisa ser declarada antes de ser usada, para que o compilador conheça sua assinatura (nome, parâmetros e tipo de retorno). A definição da função contém o corpo com as instruções que serão executadas. A declaração também é chamada de protótipo.
A definição de uma função segue a sintaxe:
tipo_de_retorno nome_da_funcao(lista_de_parametros) {
// corpo da função
return valor; // se o tipo de retorno não for void
}Por exemplo, uma função que soma dois inteiros pode ser definida assim:
int soma(int a, int b) {
return a + b;
}Nesse caso, int é o tipo de retorno, soma é o nome, e a e b são parâmetros. A função retorna a soma dos dois números.
Se a função não retorna valor, usamos void como tipo de retorno. A definição pode ser colocada antes do main ou depois, mas se for depois, é necessário um protótipo antes do uso.
Exemplo de definição antes do main:
#include <stdio.h>
int soma(int a, int b) {
return a + b;
}
int main() {
int resultado = soma(3, 4);
printf("%d\n", resultado); // 7
return 0;
}Se a função for definida depois do main, precisamos declarar o protótipo antes:
#include <stdio.h>
// Protótipo (declaração)
int soma(int a, int b);
int main() {
int resultado = soma(3, 4);
printf("%d\n", resultado); // 7
return 0;
}
// Definição depois do main
int soma(int a, int b) {
return a + b;
}Protótipos
Um protótipo de função informa ao compilador o nome da função, o tipo de retorno e os tipos dos parâmetros, sem incluir o corpo. Ele é essencial quando a função é chamada antes de sua definição, permitindo que o compilador verifique se a chamada está correta em termos de tipos e número de argumentos.
A sintaxe do protótipo é igual à da definição, mas termina com ponto e vírgula e sem o corpo:
tipo_de_retorno nome_da_funcao(lista_de_parametros);Exemplo:
int soma(int a, int b); // protótipo
Os protótipos geralmente são colocados no início do arquivo, após os #include, ou em arquivos de cabeçalho (.h). Isso permite que qualquer função chame outra sem se preocupar com a ordem de definição.
É importante que o protótipo corresponda exatamente à definição, incluindo os tipos dos parâmetros. Em C, o nome dos parâmetros no protótipo é opcional, mas é uma boa prática incluí-los para documentação.
// Protótipo sem nomes (válido)
int soma(int, int);
// Protótipo com nomes (recomendado)
int soma(int a, int b);Se o protótipo não for fornecido e a função for usada antes da definição, o compilador pode gerar um aviso ou erro, dependendo da versão do C. Em C99 e posteriores, é obrigatório ter um protótipo antes da chamada.
Parâmetros e retorno
Parâmetros são valores que a função recebe para trabalhar. Eles são definidos na lista de parâmetros entre parênteses, com tipo e nome. Quando a função é chamada, os valores passados são chamados argumentos.
Em C, os parâmetros são passados por valor, ou seja, a função recebe uma cópia do valor original. Alterações feitas nos parâmetros dentro da função não afetam as variáveis da função chamadora. Para modificar variáveis originais, é necessário usar ponteiros (veremos em aulas futuras).
O retorno é o valor que a função devolve para quem a chamou, usando a instrução return. O tipo do valor retornado deve ser compatível com o tipo de retorno declarado.
Exemplo de função com parâmetros e retorno:
#include <stdio.h>
// Função que calcula a média de dois números
float media(float x, float y) {
return (x + y) / 2.0;
}
int main() {
float a = 5.0, b = 7.0;
float m = media(a, b);
printf("Média: %.2f\n", m); // Média: 6.00
return 0;
}Também é possível ter funções com vários parâmetros de tipos diferentes, e até mesmo sem parâmetros (usando void na lista).
Uma função pode ter múltiplos return em diferentes ramos, mas apenas um será executado por chamada. Exemplo:
int maior(int a, int b) {
if (a > b) {
return a;
} else {
return b;
}
}Quando a função chega a um return, ela termina imediatamente e o valor é devolvido. Se o tipo de retorno for void, o return pode ser usado sem valor apenas para encerrar a função antecipadamente.
void
O tipo void é usado em duas situações principais: como tipo de retorno de funções que não devolvem valor, e como lista de parâmetros quando a função não recebe nenhum argumento.
Uma função void executa ações, mas não retorna um valor. Por exemplo, uma função que imprime uma mensagem:
void imprimir_mensagem() {
printf("Olá, mundo!\n");
}Nesse caso, não há return com valor. Podemos usar return; para sair mais cedo, se necessário.
Quando uma função não recebe parâmetros, escrevemos void na lista de parâmetros para explicitar que não há argumentos. Isso é opcional, mas recomendado, pois em C antigo uma lista vazia podia significar que a função aceitava qualquer número de argumentos.
// Sem parâmetros (recomendado)
void funcao(void) {
// ...
}
// Também válido, mas menos explícito
void funcao() {
// ...
}Além disso, o ponteiro void* é um ponteiro genérico que pode apontar para qualquer tipo de dado, mas isso será visto em aulas sobre ponteiros.
Exemplo completo usando void:
#include <stdio.h>
// Função que não retorna valor
void exibir_dobro(int numero) {
printf("O dobro de %d é %d\n", numero, numero * 2);
}
// Função que não recebe parâmetros e não retorna valor
void separador(void) {
printf("---\n");
}
int main() {
exibir_dobro(5);
separador();
exibir_dobro(10);
return 0;
}O uso de void também aparece em protótipos para indicar que a função não recebe argumentos, como em int main(void).
Boas práticas e observações finais
Ao trabalhar com funções, siga estas boas práticas:
- Use nomes descritivos para funções e parâmetros.
- Sempre declare protótipos para funções definidas após o
mainou em outros arquivos. - Mantenha funções pequenas e com uma única responsabilidade.
- Evite variáveis globais; prefira passar dados por parâmetros.
- Documente funções com comentários, explicando o que fazem, parâmetros e retorno.
- Use
constem parâmetros que não serão modificados, para maior segurança.
Nas próximas aulas, veremos como passar arrays para funções, usar ponteiros e criar funções recursivas.
Exercícios
- Escreva uma função chamada
quadradoque recebe um inteiro e retorna seu quadrado. Inclua o protótipo antes domaine a definição depois. Nomain, chame a função e imprima o resultado para o número 7. - Crie uma função
void saudacao(char nome[])que imprime "Olá, [nome]!" (use%s). Nomain, chame com seu nome. - Escreva uma função que recebe dois números inteiros e retorna o maior deles. Se forem iguais, retorne qualquer um. Teste com (10, 20) e (5, 5).
- Explique por que precisamos de protótipos em C e forneça um exemplo onde a ausência de protótipo causa erro de compilação.
- Escreva uma função
void mostra_par(int n)que imprime "par" se n for par e "ímpar" caso contrário. Usereturn;para sair se n for negativo. Teste com valores -3, 4 e 7.
#include <stdio.h>
// Protótipo
int quadrado(int x);
int main() {
int resultado = quadrado(7);
printf("O quadrado de 7 é %d\n", resultado);
return 0;
}
// Definição
int quadrado(int x) {
return x * x;
}#include <stdio.h>
void saudacao(char nome[]) {
printf("Olá, %s!\n", nome);
}
int main() {
saudacao("Maria");
return 0;
}#include <stdio.h>
int maior(int a, int b) {
if (a > b) {
return a;
} else {
return b;
}
}
int main() {
printf("%d\n", maior(10, 20)); // 20
printf("%d\n", maior(5, 5)); // 5
return 0;
}main e chamada antes, o compilador pode assumir que ela retorna int e não verifica os parâmetros, gerando erros ou avisos. Exemplo que gera erro em C99:#include <stdio.h>
int main() {
printf("%d\n", soma(2, 3)); // erro: soma não declarada
return 0;
}
int soma(int a, int b) {
return a + b;
}Para corrigir, adicione int soma(int a, int b); antes do main.#include <stdio.h>
void mostra_par(int n) {
if (n < 0) {
return; // sai da função
}
if (n % 2 == 0) {
printf("par\n");
} else {
printf("ímpar\n");
}
}
int main() {
mostra_par(-3); // não imprime nada
mostra_par(4); // par
mostra_par(7); // ímpar
return 0;
}