Manipulando Bibliotecas Padrão Essenciais em C

Em C, além da capacidade de incluir arquivos de cabeçalho personalizados, temos acesso a um conjunto robusto de bibliotecas padrão que oferecem funcionalidades pré-implementadas para uma vasta gama de tarefas. Este artigo explorará algumas das mais úteis, divididas por categoria.

Funções de Manipulação de Strings

A biblioteca <string.h> é fundamental para trabalhar com cadeias de caracteres. Ela fornece funções para calcular o comprimento, concatenar, copiar e comparar strings.

Determinando o Comprimento de uma String

A função strlen() retorna o número de caracteres em uma string, excluindo o terminador nulo \0.

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

int main() {
    const char* texto = "Exemplo de C!";
    // strlen retorna um valor do tipo size_t, que é um inteiro sem sinal.
    printf("O comprimento do texto é: %zu\n", strlen(texto));
    return 0;
}

Saída:

O comprimento do texto é: 13

Concatenando Strings

A função strcat() anexa uma string a outra. É crucial garantir que a string de destino tenha espaço suficiente para acomodar a string anexada.

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

int main() {
    char destino[30] = "Bem-vindo "; // Buffer com espaço suficiente
    const char* fonte = "ao mundo C!";
    
    // Concatena 'fonte' ao final de 'destino'
    strcat(destino, fonte);
    printf("String concatenada: %s\n", destino);
    return 0;
}

Saída:

String concatenada: Bem-vindo ao mundo C!

Copiando Conteúdo de Strings

A função strcpy() copia o conteúdo de uma string de origem para uma string de destino. Assim como strcat(), o buffer de destino deve ser grande o suficiente.

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

int main() {
    char buffer[20];
    const char* mensagem_original = "Olá, programador!";
    
    // Copia 'mensagem_original' para 'buffer'
    strcpy(buffer, mensagem_original);
    printf("String copiada: %s\n", buffer);
    return 0;
}

Saída:

String copiada: Olá, programador!

Comparando Strings

A função strcmp() compara duas strings lexicograficamente (baseado nos valores ASCII dos caracteres). Ela retorna um valor inteiro:

  • Menor que zero: se a primeira string for lexicograficamente menor que a segunda.
  • Zero: se as strings forem idênticas.
  • Maior que zero: se a primeira string for lexicograficamente maior que a segunda.
#include <stdio.h>
#include <string.h>

int main() {
    const char* s1 = "Apple";
    const char* s2 = "Banana";
    const char* s3 = "Apple";
    
    int resultado1 = strcmp(s1, s2); // 'A' vs 'B'
    int resultado2 = strcmp(s1, s3); // 'Apple' vs 'Apple'
    
    printf("Comparando '%s' com '%s': %d\n", s1, s2, resultado1);
    printf("Comparando '%s' com '%s': %d\n", s1, s3, resultado2);
    
    return 0;
}

Saída:

Comparando 'Apple' com 'Banana': -1
Comparando 'Apple' com 'Apple': 0

Funções Matemáticas

A biblioteca <math.h> oferece uma vasta coleção de funções para operações matemáticas complexas, como raízes, potências e funções trigonométricas. Lembre-se que, ao compilar programas C que usam <math.h>, geralmente é necessário linkar com a biblioteca matemática adicionando -lm ao comando de compilação (ex: gcc seu_codigo.c -o seu_executavel -lm).

Raiz Quadrada

A função sqrt() calcula a raiz quadrada de um número de ponto flutuante.

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

int main() {
    double valor = 25.0;
    double raiz = sqrt(valor);
    printf("A raiz quadrada de %.2f é %.2f\n", valor, raiz);
    return 0;
}

Saída:

A raiz quadrada de 25.00 é 5.00

Cálculo de Potências

A função pow() eleva um número a uma determinada potência.

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

int main() {
    double base = 3.0;
    double expoente = 4.0;
    double resultado_potencia = pow(base, expoente);
    printf("%.1f elevado a %.1f é %.1f\n", base, expoente, resultado_potencia);
    return 0;
}

Saída:

3.0 elevado a 4.0 é 81.0

Esta função pode simplificar a implementação de algoritmos, como encontrar números de Narciso (números de 3 dígitos onde a soma dos cubos de seus dígitos é igual ao próprio número):

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

int main() {
    printf("Números de Narciso de 3 dígitos:\n");
    for (int num = 100; num < 1000; ++num) {
        int d1 = num / 100;         // Centenas
        int d2 = (num / 10) % 10;   // Dezenas
        int d3 = num % 10;          // Unidades

        if (pow(d1, 3) + pow(d2, 3) + pow(d3, 3) == num) {
            printf("%d\n", num);
        }
    }
    return 0;
}

Saída:

Números de Narciso de 3 dígitos:
153
370
371
407

Funções Trigonométricas

<math.h> inclui funções como sin(), cos(), tan(), antre outras. Elas esperam ângulos em radianos.

#include <stdio.h>
#include <math.h> // Para M_PI e funções trigonométricas

int main() {
    // Calcular seno de 30 graus (PI/6 radianos)
    double angulo_rad = M_PI / 6.0; 
    printf("Seno de PI/6 (30 graus): %.4f\n", sin(angulo_rad));
    
    // Calcular tangente de 45 graus (PI/4 radianos)
    angulo_rad = M_PI / 4.0;
    printf("Tangente de PI/4 (45 graus): %.4f\n", tan(angulo_rad));
    
    // Exemplo de um caso especial: tangente de PI/2 (90 graus)
    printf("Tangente de PI/2 (90 graus): %f\n", tan(M_PI / 2.0)); // Retorna um valor muito grande ou INF
    
    return 0;
}

Saída (pode variar ligeiramente):

Seno de PI/6 (30 graus): 0.5000
Tangente de PI/4 (45 graus): 1.0000
Tangente de PI/2 (90 graus): 16331239353195370.000000

Note que tan(M_PI / 2.0) se aproxima do infinito e, devido à precisão de ponto flutuante, o resultado pode ser um número muito grande em vez de um erro explícito ou infinito.

Arredondamento e Valor Absoluto

Funções como ceil() (teto), floor() (piso) e fabs() (valor absoluto para ponto flutuante) são úteis para manipulação de números.

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

int main() {
    double num_decimal = 7.89;
    double num_negativo = -4.56;
    
    printf("Número original: %.2f\n", num_decimal);
    printf("Arredondado para cima (ceil): %.2f\n", ceil(num_decimal));
    printf("Arredondado para baixo (floor): %.2f\n", floor(num_decimal));
    
    printf("\nValor original: %.2f\n", num_negativo);
    printf("Valor absoluto (fabs): %.2f\n", fabs(num_negativo));
    
    return 0;
}

Saída:

Número original: 7.89
Arredondado para cima (ceil): 8.00
Arredondado para baixo (floor): 7.00

Valor original: -4.56
Valor absoluto (fabs): 4.56

Funções de Utilitários Gerais

A biblioteca <stdlib.h> é um tesouro de funções de uso geral, incluindo alocação de memória dinâmica, conversão de tipos e ordenação.

Ordenação de Arrays com qsort

A função qsort() implementa o algoritmo QuickSort para ordenar arrays. Ela é genérica e pode ordenar qualquer tipo de dado, desde que seja fornecida uma função de comparação.

A assinatura de qsort é void qsort(void *base, size_t num, size_t size, int (*compar)(const void *, const void *));

  • base: Ponteiro para o primeiro elemento do array a ser ordenado.
  • num: Número de elementos no array.
  • size: Tamanho de cada elemento em bytes.
  • compar: Ponteiro para uma função de comparação que define a ordem. Esta função recebe dois ponteiros const void* e deve retornar um inteiro: negativo se o primeiro elemento for menor, zero se forem iguais, ou positivo se o primeiro for maior.
#include <stdio.h>
#include <stdlib.h> // Para qsort

// Função de comparação para inteiros (ordem crescente)
int comparar_inteiros(const void* elem1, const void* elem2) {
    int val1 = *(const int*)elem1; // Converte void* para int* e desreferencia
    int val2 = *(const int*)elem2;
    return val1 - val2; // Retorna a diferença: negativo, zero ou positivo
}

int main() {
    int numeros[] = {9, 1, 5, 8, 3, 2, 7, 4, 6, 0};
    int tamanho_array = sizeof(numeros) / sizeof(numeros[0]);

    printf("Array original: ");
    for (int i = 0; i < tamanho_array; ++i) {
        printf("%d ", numeros[i]);
    }
    printf("\n");

    // Chama qsort para ordenar o array
    qsort(numeros, tamanho_array, sizeof(int), comparar_inteiros);

    printf("Array ordenado: ");
    for (int i = 0; i < tamanho_array; ++i) {
        printf("%d ", numeros[i]);
    }
    printf("\n");
    return 0;
}

Saída:

Array original: 9 1 5 8 3 2 7 4 6 0 
Array ordenado: 0 1 2 3 4 5 6 7 8 9 

Terminando um Programa com exit

A função exit() encerra o programa imediatamente. Diferente de um return da função main, que desempilha as funções e retorna o controle ao chamador, exit() fecha todos os arquivos abertos e libera buffers antes de terminar o processo. Ela recebe um código de status que é retornado ao sistema operacional.

#include <stdio.h>
#include <stdlib.h> // Para exit e EXIT_SUCCESS

int main() {
    printf("Iniciando o programa...\n");
    // Alguma condição que exige o término imediato
    if (1) { // Exemplo: se uma condição for verdadeira
        printf("Saindo do programa com sucesso.\n");
        exit(EXIT_SUCCESS); // EXIT_SUCCESS é geralmente 0
    }
    printf("Esta linha não será executada.\n"); // Não alcançável
    return 0; // Se exit() não for chamado, este return seria executado
}

Saída:

Iniciando o programa...
Saindo do programa com sucesso.

Alocação Dinâmica de Memória: malloc e free

As funções malloc() e free() são essenciais para gerenciamento de memória dinâmica. malloc() aloca um bloco de memória do tamanho especificado em bytes e retorna um ponteiro void* para o início do bloco. Se a alocação falhar, retorna NULL. free() libera um bloco de memória que foi alocado previamente por malloc, calloc ou realloc, tornando-o disponível para reuso.

#include <stdio.h>
#include <stdlib.h> // Para malloc e free

int main() {
    int* ptr_inteiro = NULL; // É uma boa prática inicializar ponteiros como NULL

    // Aloca memória para um único inteiro
    ptr_inteiro = (int*)malloc(sizeof(int)); 

    if (ptr_inteiro == NULL) {
        fprintf(stderr, "Erro ao alocar memória!\n");
        return EXIT_FAILURE; // Retorna código de erro
    }

    // Atribui um valor à memória alocada
    *ptr_inteiro = 256; 
    printf("Valor armazenado na memória alocada: %d\n", *ptr_inteiro);

    // Libera a memória alocada
    free(ptr_inteiro);
    ptr_inteiro = NULL; // Evita ponteiros "pendurados" (dangling pointers)

    printf("Memória liberada.\n");

    // Exemplo de alocação para um array de 5 doubles
    double* array_doubles = (double*)malloc(5 * sizeof(double));
    if (array_doubles == NULL) {
        fprintf(stderr, "Erro ao alocar memória para array!\n");
        return EXIT_FAILURE;
    }
    
    for (int i = 0; i < 5; ++i) {
        array_doubles[i] = i * 10.5;
        printf("array_doubles[%d] = %.1f\n", i, array_doubles[i]);
    }
    
    free(array_doubles);
    array_doubles = NULL;

    return 0;
}

Saída:

Valor armazenado na memória alocada: 256
Memória liberada.
array_doubles[0] = 0.0
array_doubles[1] = 10.5
array_doubles[2] = 21.0
array_doubles[3] = 31.5
array_doubles[4] = 42.0

A alocação e liberação de memória são passos críticos para evitar vazamentos de memória e garantir o uso eficiente dos recursos do sistema.

Tags: C StandardLibrary StringManipulation MathFunctions DynamicMemory

Publicado em 8-17 22:52