Exercícios de funções em C

Reunimos 13 exercícios em que você cria suas próprias funções, do nível iniciante ao avançado. Na maioria deles, a função main que lê a entrada e mostra o resultado já está pronta: você só precisa escrever o corpo da função pedida. Ao clicar em "Corrigir", seu código é testado com várias entradas usando gcc de verdade, e a saída é conferida.

Como usar estes exercícios
  1. Leia o enunciado e o exemplo de execução e escreva seu código no campo abaixo
  2. Clique em "▶ Executar" para testar com a sua própria entrada
  3. Clique em "✔ Corrigir" para verificar a saída com várias entradas preparadas
  4. Travou? Abra a "Dica". Resolveu? Compare com "Solução e explicação"
Regras da correção
  • Imprima a saída exatamente como no exemplo. Não imprima mensagens pedindo a entrada, como "Digite um número"
  • Espaços no fim das linhas e linhas em branco no final são ignorados
  • Seu código é salvo automaticamente neste navegador

Obs.: Executar e Corrigir enviam seu código ao Wandbox, um serviço externo e gratuito de compilação, que o executa com gcc.

13 exercícios (Iniciante 4 · Intermediário 5 · Avançado 4)

Funções (13 exercícios)

F01 Iniciante

Exercício 1. O maior de 3 números

Escreva a função int max3(int a, int b, int c), que recebe 3 inteiros e retorna o maior deles. A função main, que lê a entrada e mostra o resultado, já está pronta. A saída é "Máximo: valor".
Exemplo de execução (a entrada está sublinhada)
3 9 5 Máximo: 9
Seu código
"Executar" roda seu código com a entrada acima. "Corrigir" testa com 5 entradas preparadas.
Guarde a em uma variável m e compare com b e depois com c: "se for maior que m, substitui m". No final, devolva o valor a quem chamou com return m;.
#include <stdio.h>

int max3(int a, int b, int c) {
    int m = a;
    if (b > m) m = b;
    if (c > m) m = c;
    return m;
}

int main(void) {
    int a, b, c;
    scanf("%d %d %d", &a, &b, &c);
    printf("Máximo: %d\n", max3(a, b, c));
    return 0;
}
Explicação: O resultado de uma função é o valor devolvido com return, que toma o lugar de max3(a, b, c) no ponto em que a função foi chamada. Fazer printf dentro da função não vira valor de retorno. Se o valor inicial do máximo for 0, a função retorna 0 quando todos os números são negativos (4º teste).
F02 Iniciante

Exercício 2. Segundos em horas, minutos e segundos (função void)

Escreva a função void print_time(int sec), que recebe uma quantidade de segundos e a mostra em uma linha no formato "Hh Mmin Ss" (0 ≤ sec ≤ 1000000). Ela não retorna valor (void). A função main já está pronta.
Exemplo de execução (a entrada está sublinhada)
3661 1h 1min 1s
Seu código
"Executar" roda seu código com a entrada acima. "Corrigir" testa com 5 entradas preparadas.
Uma hora tem 3600 segundos e um minuto tem 60. As horas são sec / 3600, os minutos sec % 3600 / 60 e os segundos sec % 60. A exibição também é feita dentro da função.
#include <stdio.h>

void print_time(int sec) {
    int h = sec / 3600;
    int m = sec % 3600 / 60;
    int s = sec % 60;
    printf("%dh %dmin %ds\n", h, m, s);
}

int main(void) {
    int sec;
    scanf("%d", &sec);
    print_time(sec);
    return 0;
}
Explicação: Uma função com tipo de retorno void "não devolve valor, só faz um trabalho" (aqui, mostrar na tela). Mesmo sem escrever return, ao chegar ao fim da função a execução volta para quem a chamou. Se você calcular os minutos com sec / 60, o resultado inclui os minutos das horas (para 3661 segundos daria 61 minutos).
F03 Iniciante

Exercício 3. Função que testa ano bissexto

Escreva a função int is_leap(int year), que retorna 1 se o ano year for bissexto e 0 caso contrário (1 ≤ year ≤ 9999). Um ano é bissexto se "for divisível por 4, exceto os divisíveis por 100, mas os divisíveis por 400 são bissextos". A função main já está pronta.
Exemplo de execução (a entrada está sublinhada)
2024 O ano 2024 é bissexto
Seu código
"Executar" roda seu código com a entrada acima. "Corrigir" testa com 5 entradas preparadas.
Em uma única expressão, a condição fica (year % 4 == 0 && year % 100 != 0) || year % 400 == 0. Em C, o resultado de comparações e operações lógicas é 1 (verdadeiro) ou 0 (falso), então você pode dar return nessa expressão diretamente.
#include <stdio.h>

int is_leap(int year) {
    return (year % 4 == 0 && year % 100 != 0) || year % 400 == 0;
}

int main(void) {
    int year;
    scanf("%d", &year);
    if (is_leap(year)) {
        printf("O ano %d é bissexto\n", year);
    } else {
        printf("O ano %d não é bissexto\n", year);
    }
    return 0;
}
Explicação: Ao criar uma função de teste com nome is_xxx que retorna 1 para verdadeiro e 0 para falso, o código fica legível quase como uma frase: if (is_leap(year)). Se você testar só "divisível por 4 é bissexto", erra o ano 1900.
F04 Iniciante

Exercício 4. Celsius para Fahrenheit (retorno double)

Escreva a função double c_to_f(double c), que recebe uma temperatura c em graus Celsius e retorna a temperatura em Fahrenheit (c × 9 ÷ 5 + 32). A função main já está pronta e mostra o resultado com 1 casa decimal.
Exemplo de execução (a entrada está sublinhada)
36.5 36.5°C = 97.7°F
Seu código
"Executar" roda seu código com a entrada acima. "Corrigir" testa com 5 entradas preparadas.
Como o tipo de retorno é double, você pode devolver o resultado do cálculo diretamente, como em return c * 9.0 / 5.0 + 32.0;.
#include <stdio.h>

double c_to_f(double c) {
    return c * 9.0 / 5.0 + 32.0;
}

int main(void) {
    double c;
    scanf("%lf", &c);
    printf("%.1f°C = %.1f°F\n", c, c_to_f(c));
    return 0;
}
Explicação: Com c * 9 / 5 o cálculo sai certo porque c é double, mas se você escrever 9 / 5 * c, o 9 / 5 é calculado primeiro como divisão entre inteiros e dá 1, e o resultado fica errado. Note também que, se o tipo de retorno for int, a parte decimal é descartada.
F05 Intermediário

Exercício 5. Número de trás para frente (passagem por valor)

Escreva a função int reverse_num(int n), que recebe um inteiro n ≥ 0 (0 ≤ n ≤ 99999999) e retorna o número formado pelos seus dígitos em ordem inversa (ex.: 1230 → 321). A função main já está pronta e, depois de chamar a função, também mostra o n original.
Exemplo de execução (a entrada está sublinhada)
1234 1234 de trás para frente é 4321
Seu código
"Executar" roda seu código com a entrada acima. "Corrigir" testa com 5 entradas preparadas.
Comece o resultado r em 0 e repita "r = r * 10 + n % 10; → n /= 10;" até n chegar a 0. Não tem problema alterar n dentro da função.
#include <stdio.h>

int reverse_num(int n) {
    int r = 0;
    while (n > 0) {
        r = r * 10 + n % 10;
        n /= 10;
    }
    return r;
}

int main(void) {
    int n;
    scanf("%d", &n);
    int r = reverse_num(n);
    printf("%d de trás para frente é %d\n", n, r);
    return 0;
}
Explicação: Em C, os argumentos são passados por valor. O n que a função recebe é uma cópia do n de quem chamou, então, mesmo reduzindo-o a 0 dentro da função, o n da main não muda e o número original pode ser mostrado. Por outro lado, isso significa que alterar um argumento dentro da função não comunica nenhum resultado a quem chamou; por isso o resultado é devolvido com return.
F06 Intermediário

Exercício 6. Soma e máximo de um array

Escreva a função int sum_array(const int a[], int n), que recebe um array de int com n elementos e retorna a soma, e a função int max_array(const int a[], int n), que retorna o maior valor. A função main já está pronta: ela lê primeiro n (1 ≤ n ≤ 100), depois n inteiros (valor absoluto até 10000), e mostra a soma, o máximo e a média (com 2 casas decimais).
Exemplo de execução (a entrada está sublinhada)
5 3 8 -2 7 4 Soma: 20 Máximo: 8 Média: 4.00
Seu código
"Executar" roda seu código com a entrada acima. "Corrigir" testa com 4 entradas preparadas.
Um parâmetro que recebe array é escrito como const int a[], e o número de elementos vem em outro parâmetro, n. Para o máximo, use a[0] como máximo provisório e compare com a[1] em diante.
#include <stdio.h>

int sum_array(const int a[], int n) {
    int sum = 0;
    for (int i = 0; i < n; i++) {
        sum += a[i];
    }
    return sum;
}

int max_array(const int a[], int n) {
    int max = a[0];
    for (int i = 1; i < n; i++) {
        if (a[i] > max) max = a[i];
    }
    return max;
}

int main(void) {
    int a[100];
    int n;
    scanf("%d", &n);
    for (int i = 0; i < n; i++) {
        scanf("%d", &a[i]);
    }
    int sum = sum_array(a, n);
    printf("Soma: %d\n", sum);
    printf("Máximo: %d\n", max_array(a, n));
    printf("Média: %.2f\n", (double)sum / n);
    return 0;
}
Explicação: Dentro da função não dá para saber o tamanho do array, então a regra é passar o número de elementos junto (dentro da função, sizeof(a) não é o tamanho do array inteiro). O const indica que "esta função não altera o array". Se o valor inicial do máximo for 0, o resultado fica errado quando todos os números são negativos (3º teste).
F07 Intermediário

Exercício 7. Inverter a ordem de um array

Escreva a função void reverse_array(int a[], int n), que inverte, no próprio array, a ordem dos n elementos de um array de int. A função main já está pronta: ela lê n (1 ≤ n ≤ 100) e n inteiros, chama a função e mostra o array separado por espaços.
Exemplo de execução (a entrada está sublinhada)
5 1 2 3 4 5 5 4 3 2 1
Seu código
"Executar" roda seu código com a entrada acima. "Corrigir" testa com 5 entradas preparadas.
Troque o elemento do início a[i] com o do fim a[n - 1 - i], repetindo até a metade (i < n / 2). Use uma variável temporária tmp para a troca.
#include <stdio.h>

void reverse_array(int a[], int n) {
    for (int i = 0; i < n / 2; i++) {
        int tmp = a[i];
        a[i] = a[n - 1 - i];
        a[n - 1 - i] = tmp;
    }
}

int main(void) {
    int a[100];
    int n;
    scanf("%d", &n);
    for (int i = 0; i < n; i++) {
        scanf("%d", &a[i]);
    }
    reverse_array(a, n);
    for (int i = 0; i < n; i++) {
        printf("%d ", a[i]);
    }
    printf("\n");
    return 0;
}
Explicação: Argumentos comuns como int são passados como cópia, mas ao passar um array, o que vai de fato é a posição (endereço) do início, então alterar a[i] dentro da função muda o array da main. Se o laço for até i < n, os elementos já trocados são trocados de novo e o array volta ao que era.
F08 Intermediário

Exercício 8. Número perfeito (declaração de protótipo)

Para um inteiro positivo n (1 ≤ n ≤ 10000), escreva a função int sum_divisors(int n), que retorna a soma dos divisores de n, sem contar o próprio n. Neste exercício a definição da função fica depois da main, por isso há uma declaração de protótipo no início. A função main já está pronta: se a soma dos divisores for igual a n, mostra que é perfeito; se for maior que n, abundante; se for menor, deficiente.
Exemplo de execução (a entrada está sublinhada)
28 Soma dos divisores: 28 28 é um número perfeito
Seu código
"Executar" roda seu código com a entrada acima. "Corrigir" testa com 6 entradas preparadas.
Para i de 1 até n / 2, some i se n % i == 0 (os divisores de n, sem contar o próprio n, são todos menores ou iguais a n/2). Quando n = 1, o laço não roda nenhuma vez e o resultado é 0.
#include <stdio.h>

int sum_divisors(int n);   // declaração de protótipo

int main(void) {
    int n;
    scanf("%d", &n);
    int s = sum_divisors(n);
    printf("Soma dos divisores: %d\n", s);
    if (s == n) {
        printf("%d é um número perfeito\n", n);
    } else if (s > n) {
        printf("%d é um número abundante\n", n);
    } else {
        printf("%d é um número deficiente\n", n);
    }
    return 0;
}

int sum_divisors(int n) {
    int sum = 0;
    for (int i = 1; i <= n / 2; i++) {
        if (n % i == 0) sum += i;
    }
    return sum;
}
Explicação: O compilador C lê o código de cima para baixo, então, quando a função é definida depois do ponto em que é usada, é preciso uma declaração de protótipo que informe antes "o tipo de retorno, o nome e os tipos dos argumentos". Sem a declaração, isso é um erro a partir do padrão C99, e o compilador mostra um erro ou um aviso, dependendo do compilador. Não esqueça o ; no fim da declaração.
F09 Intermediário

Exercício 9. Conceito a partir da nota (retorno char)

Escreva a função char grade(int score), que recebe uma nota score (0 a 100) e retorna a letra do conceito: 90 ou mais é A, 80 ou mais é B, 70 ou mais é C, 60 ou mais é D e abaixo disso é F. A função main já está pronta: ela lê o número de alunos n (1 ≤ n ≤ 50) e as n notas, e mostra uma linha por aluno no formato "nota pontos: conceito".
Exemplo de execução (a entrada está sublinhada)
3 95 72 58 95 pontos: A 72 pontos: C 58 pontos: F
Seu código
"Executar" roda seu código com a entrada acima. "Corrigir" testa com 4 entradas preparadas.
Teste a partir do limite mais alto, como em if (score >= 90) return 'A';, e dê return assim que uma condição for satisfeita. Caracteres são escritos entre aspas simples, como 'A'.
#include <stdio.h>

char grade(int score) {
    if (score >= 90) return 'A';
    if (score >= 80) return 'B';
    if (score >= 70) return 'C';
    if (score >= 60) return 'D';
    return 'F';
}

int main(void) {
    int n;
    scanf("%d", &n);
    for (int i = 0; i < n; i++) {
        int score;
        scanf("%d", &score);
        printf("%d pontos: %c\n", score, grade(score));
    }
    return 0;
}
Explicação: Ao executar return, a função termina naquele ponto, então os testes seguintes não são feitos mesmo sem escrever else. "A" (aspas duplas) é uma string e não pode ser o valor de retorno de tipo char. Os testes conferem os limites exatos de 90, 80, 70 e 60 pontos.
F10 Avançado

Exercício 10. O máximo foi atualizado? (variável static)

Escreva a função int is_new_max(int x), que recebe um inteiro x a cada chamada e retorna 1 se x for maior que todos os valores recebidos até agora (ou se for a primeira chamada), e 0 caso contrário. Guarde o máximo até o momento em uma variável static dentro da função (não use variáveis globais). A função main já está pronta: ela passa n inteiros (1 ≤ n ≤ 50) para a função, um de cada vez, e mostra uma linha "valor: novo máximo" ou "valor: -" para cada um.
Exemplo de execução (a entrada está sublinhada)
5 3 1 4 1 5 3: novo máximo 1: - 4: novo máximo 1: - 5: novo máximo
Seu código
"Executar" roda seu código com a entrada acima. "Corrigir" testa com 4 entradas preparadas.
Coloque duas variáveis dentro da função: static int max; e static int first = 1;. Variáveis static mantêm o valor mesmo depois que a função termina, e são inicializadas uma única vez, no início do programa. Se first for 1, trate como "primeira vez".
#include <stdio.h>

int is_new_max(int x) {
    static int first = 1;
    static int max;

    if (first || x > max) {
        first = 0;
        max = x;
        return 1;
    }
    return 0;
}

int main(void) {
    int n;
    scanf("%d", &n);
    for (int i = 0; i < n; i++) {
        int x;
        scanf("%d", &x);
        if (is_new_max(x)) {
            printf("%d: novo máximo\n", x);
        } else {
            printf("%d: -\n", x);
        }
    }
    return 0;
}
Explicação: Uma variável local comum, sem static, é criada de novo a cada chamada, então não consegue lembrar o máximo da vez anterior. Além disso, se o valor inicial do máximo for 0, quando só há números negativos (2º teste) o primeiro valor não vira "novo máximo". Por isso, controlamos "se é a primeira vez" com outra variável static. Uma variável static só é visível dentro da sua função, o que a torna mais segura que uma variável global.
F11 Avançado

Exercício 11. Depósitos e saques (variável global)

Usando a variável global balance (valor inicial 0), que representa o saldo, escreva a função de depósito void deposit(int amount) e a função de saque int withdraw(int amount). withdraw diminui o saldo e retorna 1 se houver saldo suficiente; caso contrário, retorna 0 sem alterar o saldo. A função main já está pronta: ela lê o número de operações n (1 ≤ n ≤ 20) e n linhas no formato "d valor" (depósito) ou "w valor" (saque), com valores de 1 a 100000.
Exemplo de execução (a entrada está sublinhada)
3 d 1000 w 300 w 800 Depósito 1000: saldo 1000 Saque 300: saldo 700 Saque 800: saldo insuficiente (saldo 700) Saldo final: 700
Seu código
"Executar" roda seu código com a entrada acima. "Corrigir" testa com 4 entradas preparadas.
Como a variável global é declarada fora das funções, qualquer função pode lê-la e alterá-la diretamente, como em balance += amount;. Em withdraw, trate primeiro o caso de falha com if (amount > balance) return 0;.
#include <stdio.h>

int balance = 0;   // saldo (variável global)

void deposit(int amount) {
    balance += amount;
}

int withdraw(int amount) {
    if (amount > balance) {
        return 0;
    }
    balance -= amount;
    return 1;
}

int main(void) {
    int n;
    scanf("%d", &n);
    for (int i = 0; i < n; i++) {
        char cmd;
        int amount;
        scanf(" %c %d", &cmd, &amount);
        if (cmd == 'd') {
            deposit(amount);
            printf("Depósito %d: saldo %d\n", amount, balance);
        } else if (withdraw(amount)) {
            printf("Saque %d: saldo %d\n", amount, balance);
        } else {
            printf("Saque %d: saldo insuficiente (saldo %d)\n", amount, balance);
        }
    }
    printf("Saldo final: %d\n", balance);
    return 0;
}
Explicação: Se você escrever int balance = 0; dentro da função, é criada uma nova variável local com o mesmo nome, e a variável global não muda (ocultação de nome). Um saque igual ao saldo (a 2ª operação, w 500) deve dar certo, então a condição é amount > balance. Variáveis globais são práticas porque podem ser alteradas de qualquer lugar, mas, justamente por isso, fica difícil rastrear onde mudaram; use-as só quando necessário.
F12 Avançado

Exercício 12. Que dia do ano é? (combinando funções)

Escreva a função int days_in_month(int y, int m), que recebe o ano y e o mês m (1 a 12) e retorna o número de dias desse mês, e a função int day_of_year(int y, int m, int d), que recebe ano, mês e dia e retorna qual é o dia do ano, contando a partir de 1º de janeiro. A função de ano bissexto is_leap e a função main já estão prontas. A entrada é sempre uma data válida (1 ≤ y ≤ 9999).
Exemplo de execução (a entrada está sublinhada)
2024 3 1 Dias em 3/2024: 31 1/3/2024 é o dia 61 do ano
Seu código
"Executar" roda seu código com a entrada acima. "Corrigir" testa com 7 entradas preparadas.
Guarde os dias de cada mês em um array {31, 28, 31, 30, ...} e retorne 29 se for fevereiro em ano bissexto. day_of_year é "a soma dos dias dos meses 1 a m−1 + d", então dá para fazer chamando days_in_month repetidamente.
#include <stdio.h>

int is_leap(int y) {
    return (y % 4 == 0 && y % 100 != 0) || y % 400 == 0;
}

int days_in_month(int y, int m) {
    const int days[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    if (m == 2 && is_leap(y)) {
        return 29;
    }
    return days[m - 1];
}

int day_of_year(int y, int m, int d) {
    int total = d;
    for (int i = 1; i < m; i++) {
        total += days_in_month(y, i);
    }
    return total;
}

int main(void) {
    int y, m, d;
    scanf("%d %d %d", &y, &m, &d);
    printf("Dias em %d/%d: %d\n", m, y, days_in_month(y, m));
    printf("%d/%d/%d é o dia %d do ano\n", d, m, y, day_of_year(y, m, d));
    return 0;
}
Explicação: Criando funções pequenas e chamando-as a partir de outras funções, o tratamento do ano bissexto fica concentrado em um só lugar. Os índices de um array começam em 0, então os dias do mês m estão em days[m - 1]. Se o laço for até i <= m, os dias do próprio mês também são somados.
F13 Avançado

Exercício 13. Ordenar um array em ordem crescente

Escreva a função void sort_array(int a[], int n), que ordena um array de int com n elementos em ordem crescente. O método é livre (bubble sort, selection sort etc.). A função print_array, que mostra o array, e a função main já estão prontas: a main lê n (1 ≤ n ≤ 100) e n inteiros e mostra o array antes e depois da ordenação.
Exemplo de execução (a entrada está sublinhada)
6 5 2 9 1 5 6 Antes: 5 2 9 1 5 6 Depois: 1 2 5 5 6 9
Seu código
"Executar" roda seu código com a entrada acima. "Corrigir" testa com 5 entradas preparadas.
No bubble sort, dentro de um laço externo com i de 0 a n−2, faça um laço com j de 0 a n−2−i e troque os vizinhos se a[j] > a[j + 1]. A cada volta, o maior valor restante fica definido na ponta direita.
#include <stdio.h>

void print_array(const char label[], const int a[], int n) {
    printf("%s:", label);
    for (int i = 0; i < n; i++) {
        printf(" %d", a[i]);
    }
    printf("\n");
}

void sort_array(int a[], int n) {
    for (int i = 0; i < n - 1; i++) {
        for (int j = 0; j < n - 1 - i; j++) {
            if (a[j] > a[j + 1]) {
                int tmp = a[j];
                a[j] = a[j + 1];
                a[j + 1] = tmp;
            }
        }
    }
}

int main(void) {
    int a[100];
    int n;
    scanf("%d", &n);
    for (int i = 0; i < n; i++) {
        scanf("%d", &a[i]);
    }
    print_array("Antes", a, n);
    sort_array(a, n);
    print_array("Depois", a, n);
    return 0;
}
Explicação: Como as alterações feitas em um array dentro da função aparecem também para quem chamou, dá para criar uma função que "ordena" sem valor de retorno (void). Se o laço interno for até j < n, a[j + 1] lê fora dos limites do array (a[n]); por isso usamos j < n - 1 - i.

Revise estas aulas

← Voltar para todos os exercícios