Funções

Organizando código em blocos reutilizáveis com parâmetros e retorno.

Conforme seu programa cresce, você vai notar que repete o mesmo código em vários lugares. Funções resolvem isso: você escreve a lógica uma vez e chama quando precisar.

Conforme Linguagem C Completa e Descomplicada (André Backes): “Os comandos da função são executados. Quando a função termina, o programa volta ao ponto em que foi interrompido para continuar sua execução normal.”

Anatomia de uma Função

tipo_retorno nome_funcao(tipo param1, tipo param2) {
    // corpo da função
    return valor;
}

Exemplo completo:

// Definição da função
int somar(int a, int b) {
    int resultado = a + b;
    return resultado;
}

int main() {
    // Chamando a função
    int total = somar(5, 3);
    printf("5 + 3 = %d\n", total);  // Imprime: 5 + 3 = 8
    return 0;
}

Parâmetros vs Argumentos

  • Parâmetros: As variáveis declaradas na definição da função (int a, int b)
  • Argumentos: Os valores passados na chamada (5, 3)
//        Parâmetros
//            ↓↓
int somar(int a, int b) { ... }

//      Argumentos
//          ↓↓
somar(5, 3);

Tipo de Retorno

O tipo antes do nome define o que a função devolve:

int calcular_idade(int ano_nascimento) {
    return 2024 - ano_nascimento;  // Retorna um int
}

float calcular_media(int a, int b) {
    return (a + b) / 2.0;  // Retorna um float
}

Função sem Retorno: void

Use void quando a função não precisa devolver valor:

void exibir_mensagem(char *texto) {
    printf(">>> %s <<<\n", texto);
    // Sem return (ou "return;" sem valor)
}

int main() {
    exibir_mensagem("Olá!");
    return 0;
}

Declaração vs Definição

Em C, o compilador lê de cima para baixo. Se você chamar uma função antes de defini-la, dará erro:

int main() {
    somar(5, 3);  // ERRO: 'somar' não foi declarada ainda!
    return 0;
}

int somar(int a, int b) { return a + b; }

Solução 1: Defina a função antes de usar

int somar(int a, int b) { return a + b; }

int main() {
    somar(5, 3);  // OK
    return 0;
}

Solução 2: Declare um protótipo no início

// Protótipo (promessa que a função existe)
int somar(int a, int b);

int main() {
    somar(5, 3);  // OK, compilador confia no protótipo
    return 0;
}

// Definição (implementação real)
int somar(int a, int b) {
    return a + b;
}

Boa Prática

Em projetos reais, protótipos ficam em arquivos .h (headers), e as implementações em arquivos .c. Isso será abordado em módulos posteriores.

Passagem por Valor

Em C, parâmetros são copiados. Modificar o parâmetro dentro da função não afeta a variável original:

void dobrar(int x) {
    x = x * 2;  // Modifica apenas a CÓPIA
    printf("Dentro: %d\n", x);
}

int main() {
    int numero = 10;
    dobrar(numero);
    printf("Fora: %d\n", numero);  // Ainda é 10!
    return 0;
}

Saída:

Dentro: 20
Fora: 10

Para modificar a variável original, você precisará de ponteiros (próximo módulo).

Escopo de Variáveis

O escopo define onde uma variável é visível:

Variáveis Locais

Existem apenas dentro da função onde foram declaradas:

void funcao_a() {
    int x = 10;  // x existe apenas aqui
}

void funcao_b() {
    printf("%d", x);  // ERRO: x não existe aqui!
}

Variáveis Globais

Declaradas fora de qualquer função, visíveis em todo o arquivo:

int contador = 0;  // Global

void incrementar() {
    contador++;  // Acessa a global
}

int main() {
    incrementar();
    incrementar();
    printf("%d\n", contador);  // Imprime: 2
    return 0;
}

Evite Globais

Variáveis globais são tentadoras, mas tornam o código difícil de entender e depurar. Prefira passar valores como parâmetros.

Exemplo Prático: Calculadora

#include <stdio.h>

// Protótipos
float somar(float a, float b);
float subtrair(float a, float b);
float multiplicar(float a, float b);
float dividir(float a, float b);
void exibir_menu();

int main() {
    float num1, num2, resultado;
    int opcao;

    exibir_menu();
    scanf("%d", &opcao);

    printf("Digite dois números: ");
    scanf("%f %f", &num1, &num2);

    switch (opcao) {
        case 1:
            resultado = somar(num1, num2);
            break;
        case 2:
            resultado = subtrair(num1, num2);
            break;
        case 3:
            resultado = multiplicar(num1, num2);
            break;
        case 4:
            resultado = dividir(num1, num2);
            break;
        default:
            printf("Opção inválida!\n");
            return 1;
    }

    printf("Resultado: %.2f\n", resultado);
    return 0;
}

// Implementações
void exibir_menu() {
    printf("=== Calculadora ===\n");
    printf("1. Somar\n");
    printf("2. Subtrair\n");
    printf("3. Multiplicar\n");
    printf("4. Dividir\n");
    printf("Escolha: ");
}

float somar(float a, float b) {
    return a + b;
}

float subtrair(float a, float b) {
    return a - b;
}

float multiplicar(float a, float b) {
    return a * b;
}

float dividir(float a, float b) {
    if (b == 0) {
        printf("Erro: Divisão por zero!\n");
        return 0;
    }
    return a / b;
}

Próximo Passo

Você agora sabe estruturar código em funções. No próximo módulo, vou mergulhar em ponteiros e memória — o recurso mais poderoso (e perigoso) do C.

Progresso do Tópico