A Biblioteca Padrão

A biblioteca padrão é como uma caixa de ferramentas — você não precisa forjar seu próprio martelo e chave de fenda, basta pegá-los e usá-los. Entender o que cada ferramenta faz ajuda você a escolher a certa.

math.h Operações Matemáticas

Usar funções matemáticas requer incluir o cabeçalho e linkar a biblioteca matemática:

C
#include <math.h>

Compile com a flag -lm: gcc programa.c -lm.

Funções Matemáticas Comuns

Função Finalidade Exemplo
fabs(x) Valor absoluto fabs(-3.5) → 3.5
sqrt(x) Raiz quadrada sqrt(16.0) → 4.0
pow(x, y) x elevado à potência y pow(2.0, 10.0) → 1024.0
ceil(x) Arredondar para cima ceil(3.2) → 4.0
floor(x) Arredondar para baixo floor(3.8) → 3.0
round(x) Arredondar para o mais próximo round(3.5) → 4.0
fmod(x, y) Resto de ponto flutuante fmod(7.5, 2.5) → 0.0
log(x) Logaritmo natural log(2.718) → 1.0
log10(x) Logaritmo comum log10(100.0) → 2.0
sin(x) Seno sin(3.14/2) → 1.0
cos(x) Cosseno cos(0.0) → 1.0
tan(x) Tangente tan(0.0) → 0.0
⚠️ Atenção: Funções trigonométricas recebem radianos, não graus! Para converter graus em radianos: rad = grau * 3.14159265 / 180.0.

Exemplo

Calcular a distância entre dois pontos:

C
#include <stdio.h>
#include <math.h>

typedef struct {
    double x;
    double y;
} Point;

double distance(Point a, Point b) {
    double dx = a.x - b.x;
    double dy = a.y - b.y;
    return sqrt(dx * dx + dy * dy);
}

int main(void) {
    Point p1 = {3.0, 4.0};
    Point p2 = {0.0, 0.0};
    printf("Distância: %.2f\n", distance(p1, p2));
    return 0;
}
▶ Experimente
TEXT
Distância: 5.00

stdlib.h Utilitários Gerais

Números Aleatórios

C
int rand(void);
void srand(unsigned int seed);

rand() retorna um inteiro pseudo-aleatório entre 0 e RAND_MAX. Sem chamar srand, cada execução do programa produz a mesma sequência de números aleatórios.

C
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main(void) {
    srand((unsigned int)time(NULL));

    for (int i = 0; i < 5; i++) {
        printf("%d ", rand());
    }
    printf("\n");

    for (int i = 0; i < 5; i++) {
        printf("%d ", rand() % 100);
    }
    printf("\n");

    return 0;
}
TEXT
1804289383 846930886 1681692777 1714636915 1957747793
83 86 77 15 93
⚠️ Atenção: rand() % N não fornece boa aleatoriedade na maioria das implementações — bits baixos podem seguir um padrão. Para cenários que requerem aleatoriedade de alta qualidade, use um gerador de números aleatórios mais avançado.

Conversão de Tipos

Função Finalidade
atoi(str) String para int
atol(str) String para long
atof(str) String para double
strtol(str, &end, base) String para long (com base)
strtod(str, &end) String para double (com detecção de erro)
C
#include <stdio.h>
#include <stdlib.h>

int main(void) {
    int a = atoi("42");
    double b = atof("3.14");
    long c = strtol("0xFF", NULL, 16);

    printf("a = %d\n", a);
    printf("b = %.2f\n", b);
    printf("c = %ld\n", c);

    char *end;
    long d = strtol("123abc", &end, 10);
    printf("d = %ld, Parte não convertida: %s\n", d, end);

    return 0;
}
TEXT
a = 42
b = 3.14
c = 255
d = 123, Parte não convertida: abc
💡 Dica: atoi não pode detectar erros — entrada inválida retorna 0, o que é indistinguível de um 0 legítimo. Prefira strtol/strtod, que permitem determinar se a conversão foi bem-sucedida através do ponteiro end.

Gerenciamento de Memória Dinâmica

C
void *malloc(size_t size);
void *calloc(size_t count, size_t size);
void *realloc(void *ptr, size_t size);
void free(void *ptr);
C
#include <stdio.h>
#include <stdlib.h>

int main(void) {
    int *arr = calloc(5, sizeof(int));
    if (arr == NULL) {
        return 1;
    }

    for (int i = 0; i < 5; i++) {
        arr[i] = i * 10;
    }

    int *new_arr = realloc(arr, 10 * sizeof(int));
    if (new_arr == NULL) {
        free(arr);
        return 1;
    }
    arr = new_arr;

    for (int i = 5; i < 10; i++) {
        arr[i] = i * 10;
    }

    for (int i = 0; i < 10; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");

    free(arr);
    return 0;
}
TEXT
0 10 20 30 40 50 60 70 80 90
⚠️ Atenção: Quando realloc falha, ela retorna NULL mas a memória original não é liberada! Portanto você deve usar uma variável temporária para receber o valor de retorno do realloc — em caso de falha, você ainda pode liberar a memória original.

Ordenação e Busca

qsort

C
void qsort(void *base, size_t count, size_t size,
           int (*compare)(const void *, const void *));

Regras da função de comparação: retorna negativo se a < b, 0 se igual, positivo se a > b.

C
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int cmp_int(const void *a, const void *b) {
    return *(const int *)a - *(const int *)b;
}

int cmp_str(const void *a, const void *b) {
    return strcmp(*(const char )a, *(const char )b);
}

int main(void) {
    int nums[] = {42, 17, 8, 95, 3, 61};
    int n = sizeof(nums) / sizeof(nums[0]);

    qsort(nums, n, sizeof(int), cmp_int);
    for (int i = 0; i < n; i++) {
        printf("%d ", nums[i]);
    }
    printf("\n");

    const char *names[] = {"Alice", "Bob", "Charlie", "Diana"};
    int m = sizeof(names) / sizeof(names[0]);

    qsort(names, m, sizeof(char *), cmp_str);
    for (int i = 0; i < m; i++) {
        printf("%s ", names[i]);
    }
    printf("\n");

    return 0;
}
TEXT
3 8 17 42 61 95
Alice Bob Charlie Diana

bsearch

C
void *bsearch(const void *key, const void *base, size_t count,
              size_t size, int (*compare)(const void *, const void *));

Realiza busca binária em um array ordenado. Retorna um ponteiro para o elemento encontrado, ou NULL se não encontrado.

C
#include <stdio.h>
#include <stdlib.h>

int cmp_int(const void *a, const void *b) {
    return *(const int *)a - *(const int *)b;
}

int main(void) {
    int nums[] = {3, 8, 17, 42, 61, 95};
    int n = sizeof(nums) / sizeof(nums[0]);

    int key = 42;
    int *result = bsearch(&key, nums, n, sizeof(int), cmp_int);

    if (result != NULL) {
        printf("Encontrado %d no índice %ld\n", key, result - nums);
    } else {
        printf("%d não encontrado\n", key);
    }

    return 0;
}
TEXT
Encontrado 42 no índice 3

time.h Tratamento de Tempo

Funções de Tempo

Função/Tipo Finalidade
time_t Tipo de tempo (geralmente segundos desde 1970-01-01)
time(&t) Obter tempo atual
clock() Obter ticks de clock da CPU usados pelo programa
localtime() Converter para struct de tempo local
gmtime() Converter para struct de tempo UTC
strftime() Formatar tempo como string
difftime() Calcular diferença entre dois tempos (segundos)

struct tm

C
struct tm {
    int tm_sec;
    int tm_min;
    int tm_hour;
    int tm_mday;
    int tm_mon;
    int tm_year;
    int tm_wday;
    int tm_yday;
    int tm_isdst;
};

tm_mon varia de 0-11 (0 = Janeiro), tm_year é o número de anos desde 1900, e tm_wday usa 0 para Domingo.

Exemplo

C
#include <stdio.h>
#include <time.h>

int main(void) {
    time_t now = time(NULL);
    struct tm *local = localtime(&now);

    char buf[64];
    strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", local);
    printf("Hora atual: %s\n", buf);

    printf("Hoje é o dia %d da semana (0=Dom)\n", local->tm_wday);

    return 0;
}
▶ Experimente
TEXT
Hora atual: 2025-03-15 14:30:22
Hoje é o dia 6 da semana (0=Dom)

Cronometragem de Programa

C
#include <stdio.h>
#include <time.h>

int main(void) {
    clock_t start = clock();

    volatile long sum = 0;
    for (long i = 0; i < 100000000L; i++) {
        sum += i;
    }

    clock_t end = clock();
    double elapsed = (double)(end - start) / CLOCKS_PER_SEC;
    printf("Tempo decorrido: %.3f segundos\n", elapsed);

    return 0;
}
TEXT
Tempo decorrido: 0.235 segundos
⚠️ Atenção: clock() mede tempo de CPU, não tempo de relógio de parede. Se o programa tem esperas de sleep ou I/O, esse tempo não é contado. Use difftime para medir o tempo decorrido real.

ctype.h Tratamento de Caracteres

Função Condição Testada
isalpha(c) Letra
isdigit(c) Dígito
isalnum(c) Letra ou dígito
isupper(c) Letra maiúscula
islower(c) Letra minúscula
isspace(c) Espaço em branco (espaço, tab, nova linha, etc.)
ispunct(c) Pontuação
isprint(c) Caractere imprimível
toupper(c) Converter para maiúscula
tolower(c) Converter para minúscula

Essas funções requerem um valor unsigned char ou EOF como argumento. Passar um valor char negativo é comportamento indefinido.

Exemplo

Contar letras, dígitos e outros caracteres em uma string:

C
#include <stdio.h>
#include <ctype.h>

int main(void) {
    char str[] = "Olá, Mundo! 123";
    int letters = 0, digits = 0, others = 0;

    for (int i = 0; str[i] != '\0'; i++) {
        if (isalpha((unsigned char)str[i])) {
            letters++;
        } else if (isdigit((unsigned char)str[i])) {
            digits++;
        } else {
            others++;
        }
    }

    printf("Letras: %d, Dígitos: %d, Outros: %d\n", letters, digits, others);
    return 0;
}
▶ Experimente
TEXT
Letras: 10, Dígitos: 3, Outros: 6

assert.h Asserções

C
void assert(int expression);

Quando a expressão é falsa, o programa termina e exibe uma mensagem de erro (nome do arquivo, número da linha, expressão). Definir a macro NDEBUG antes de #include <assert.h> desabilita todas as asserções.

C
#include <stdio.h>
#include <assert.h>

double safe_divide(double a, double b) {
    assert(b != 0 && "Divisor não pode ser zero");
    return a / b;
}

int main(void) {
    printf("10 / 2 = %.1f\n", safe_divide(10.0, 2.0));
    printf("10 / 0 = %.1f\n", safe_divide(10.0, 0.0));
    return 0;
}
TEXT
10 / 2 = 5.0
Assertion failed: b != 0 && "Divisor não pode ser zero", file main.c, line 5
💡 Dica: O literal de string em assert é impresso, então escrever "Divisor não pode ser zero" é mais eficaz que um comentário — quando a asserção falha, você pode ver imediatamente o motivo.

❓ Perguntas Frequentes

P: Por que rand() produz a mesma sequência em cada execução? R: Nenhuma chamada a srand foi feita para definir a semente aleatória. A semente padrão é 1, então a sequência é fixa. Use srand(time(NULL)) para semear com o tempo atual.

P: Por que a função de comparação do qsort usa ponteiros void? R: qsort é uma função genérica que não sabe que tipo está ordenando. Ponteiros void podem apontar para qualquer tipo, e a função de comparação os converte de volta ao tipo específico internamente.

P: Por que argumentos de funções ctype.h devem ser convertidos para unsigned char? R: Se char é com sinal, caracteres com o bit alto definido podem ser valores negativos, o que é comportamento indefinido quando passado para funções ctype. Converter para unsigned char garante que o valor esteja na faixa 0-255.

P: Qual a diferença entre assert e uma verificação if? R: assert verifica coisas que nunca deveriam acontecer (erros lógicos) durante o desenvolvimento, e desaparece quando NDEBUG é definido. Verificações if tratam erros de tempo de execução que podem ocorrer e estão sempre presentes.

📖 Resumo

📝 Exercícios

  1. Escreva um programa que gere 100 inteiros aleatórios de 1 a 1000, ordene-os com qsort e exiba os valores máximo e mínimo
  2. Escreva um programa que use clock() para comparar a diferença de tempo entre bubble sort e qsort em 10.000 inteiros
  3. Escreva uma função que use funções ctype.h para implementar conversão de maiúsculas/minúsculas de string (entrada uma string, saída versão toda maiúscula e toda minúscula)
100%