gu.pro.br
Nossa libft para estudar ANSI C

Nossa libft para estudar ANSI C

Quer aprender como criar uma biblioteca personalizada em C? Neste tutorial, vamos explorar a construção de uma biblioteca simples chamada libft, detalhando as funções e conceitos subjacentes que você precisa entender.

Libft é uma biblioteca de funções personalizadas criadas em linguagem C, seguindo o padrão ANSI C. Essas funções são geralmente implementações alternativas ou complementares às funções da biblioteca padrão C (stdlib.h, string.h, etc.).

Uma libft é uma biblioteca de funções personalizadas em ANSI C, criada para aprendizado, personalização e reutilização. Ela pode incluir funções de diversas áreas, como manipulação de strings, listas encadeadas, funções matemáticas e entrada/saída.

Por que criar uma libft?

  • Aprendizado: A criação de uma libft é uma excelente maneira de aprender os conceitos fundamentais da programação em C, como ponteiros, alocação de memória, estruturas de dados e algoritmos.
  • Personalização: Você pode implementar funções de acordo com suas necessidades específicas, tornando seu código mais eficiente ou mais flexível.
  • Reutilização: Uma vez criada, a libft pode ser reutilizada em diferentes projetos, economizando tempo e esforço.

Exemplos de funções comuns em uma libft:

  • Manipulação de strings: ft_strlen, ft_strcpy, ft_strcmp, ft_strjoin, etc.
  • Listas encadeadas: ft_lstnew, ft_lstadd_front, ft_lstsize, etc.
  • Funções matemáticas: ft_sqrt, ft_pow, etc.
  • Funções de entrada e saída: ft_putchar, ft_putstr, etc.

Observações:

  • A implementação de uma libft pode variar de pessoa para pessoa, mas geralmente segue os mesmos princípios básicos.
  • É importante garantir que as funções da libft sejam eficientes e robustas, evitando erros de memória ou comportamentos inesperados.
  • A libft pode ser compartilhada com outros desenvolvedores, contribuindo para a comunidade de programação C.

Nosso breve escopo será:

Manipulação de Strings e Memória

  • ft_strlen: Calcula o comprimento da string.
  • Conceito: Percorrer a memória até encontrar o caractere nulo (\0), uma técnica essencial para o gerenciamento de strings em C.
  • ft_strcpy: Copia uma string para outra.
  • Conceito: Manipulação direta de memória, onde você precisa garantir que o buffer de destino é grande o suficiente para a string copiada.
  • ft_memcpy: Copia uma área de memória para outra.
  • Conceito: Utiliza ponteiros para copiar blocos de memória, crucial para operações eficientes em sistemas de baixo nível.
  • ft_memset: Preenche uma área de memória com um valor.
  • Conceito: Utiliza um loop para definir bytes de memória, comum em inicialização de buffers e estruturas de dados.

Conversão de Tipos e Parsing

  • ft_atoi: Converte uma string em um inteiro.
  • Conceito: Parsing de dados, onde você interpreta uma sequência de caracteres e converte para um tipo numérico, fundamental para leitura de dados e processamento.

Gerenciamento de Recursos

  • Makefile: Automatiza a construção da biblioteca.
  • Conceito: Gerenciamento de build, onde você usa ferramentas para compilar e linkar código, melhorando a eficiência e organização do desenvolvimento.

1. Configuração Inicial

Primeiro, crie um diretório para seu projeto e os arquivos necessários:

mkdir libft
cd libft
touch libft.h
touch libft.c
touch Makefile

2. Definindo o Cabeçalho (libft.h)

O arquivo de cabeçalho define as funções disponíveis na biblioteca. Aqui está um exemplo básico:

// libft.h

#ifndef LIBFT_H
#define LIBFT_H

#include <stddef.h>

// Funções de manipulação de strings
size_t ft_strlen(const char *str);
char *ft_strcpy(char *dest, const char *src);

// Funções de manipulação de memória
void *ft_memcpy(void *dest, const void *src, size_t n);
void *ft_memset(void *s, int c, size_t n);

// Funções úteis
int ft_atoi(const char *str);

#endif

3. Implementando as Funções (libft.c)

Aqui está como você pode implementar essas funções:

// libft.c

#include "libft.h"

// Calcula o comprimento de uma string
size_t ft_strlen(const char *str) {
size_t len = 0;
while (str[len] != '\0') {
len++;
}
return len;
}

// Copia uma string para outra
char *ft_strcpy(char *dest, const char *src) {
char *d = dest;
while ((*d++ = *src++)) {
// Copia até o caractere nulo
}
return dest;
}

// Copia uma área de memória para outra
void *ft_memcpy(void *dest, const void *src, size_t n) {
unsigned char *d = dest;
const unsigned char *s = src;
while (n--) {
*d++ = *s++;
}
return dest;
}

// Preenche uma área de memória com um valor
void *ft_memset(void *s, int c, size_t n) {
unsigned char *p = s;
while (n--) {
*p++ = (unsigned char)c;
}
return s;
}

// Converte uma string para um inteiro
int ft_atoi(const char *str) {
int result = 0;
while (*str >= '0' && *str <= '9') {
result = result * 10 + (*str - '0');
str++;
}
return result;
}

4. Criando o Makefile

O Makefile automatiza a compilação da biblioteca:

# Makefile

NAME = libft.a
CC = gcc
CFLAGS = -Wall -Wextra -Werror
SRCS = libft.c
OBJS = $(SRCS:.c=.o)

all: $(NAME)

$(NAME): $(OBJS)
ar rcs $(NAME) $(OBJS)

%.o: %.c
$(CC) $(CFLAGS) -c $< -o $@

clean:
rm -f $(OBJS)

fclean: clean
rm -f $(NAME)

re: fclean all

5. Compilando e Usando a Biblioteca

Compile a biblioteca com:

make

Para usar a biblioteca em outro projeto, inclua libft.h e link com libft.a:

gcc main.c -L. -lft -o my_program

6. Conceitos Científicos e Técnicos Envolvidos

1. ft_strlen

Função: Calcula o comprimento de uma string.

Detalhes Internos:

  • Algoritmo: Percorre a memória a partir do início da string até encontrar o caractere nulo (\0), que indica o fim da string.
  • Complexidade: O tempo de execução é O(n), onde n é o comprimento da string. Isso porque a função precisa verificar cada caractere uma vez.
  • Aspectos de Memória: Strings em C são armazenadas em blocos contínuos de memória. O caractere nulo é usado para demarcar o fim da string, permitindo que funções como ft_strlen saibam quando parar de contar.

2. ft_strcpy

Função: Copia uma string de um local para outro.

Detalhes Internos:

  • Algoritmo: Utiliza um loop para copiar cada caractere da string fonte para a string destino, incluindo o caractere nulo no final.
  • Complexidade: O tempo de execução também é O(n), onde n é o comprimento da string, pois cada caractere deve ser copiado.
  • Aspectos de Memória: A cópia direta exige que o buffer de destino seja suficientemente grande para acomodar a string fonte e o caractere nulo. A falta de verificação de tamanhos pode levar a vulnerabilidades como estouro de buffer.

3. ft_memcpy

Função: Copia uma área de memória para outra.

Detalhes Internos:

  • Algoritmo: Utiliza ponteiros para copiar um bloco de memória de uma localização para outra. Normalmente, o algoritmo é implementado em termos de cópia byte a byte.
  • Complexidade: O tempo de execução é O(n), onde n é o número de bytes a serem copiados. A cópia é feita em uma única passagem através da memória.
  • Aspectos de Memória: A função deve lidar com possíveis sobreposições entre a área de origem e a área de destino. Em casos onde as áreas se sobrepõem, memmove deve ser usado em vez de memcpy para evitar problemas.

4. ft_memset

Função: Preenche uma área de memória com um valor específico.

Detalhes Internos:

  • Algoritmo: Utiliza um loop para definir cada byte da área de memória para o valor especificado. Pode usar otimizações, como preenchimento por palavras, para melhorar o desempenho.
  • Complexidade: O tempo de execução é O(n), onde n é o número de bytes a serem preenchidos. A função percorre a área de memória uma vez.
  • Aspectos de Memória: É comumente usado para inicializar buffers antes de seu uso. É importante garantir que o tamanho da memória a ser preenchida não exceda o alocado, para evitar corrupção de dados ou falhas de segmentação.

Conceitos Técnicos e Científicos

  • Manipulação Direta de Memória: Essas operações envolvem o acesso direto e modificação de locais específicos na memória. A habilidade de manipular diretamente a memória é fundamental para a programação em sistemas de baixo nível e desenvolvimento de sistemas operacionais.
  • Endereçamento e Ponteiros: O uso de ponteiros é essencial para operações como cópia de memória. Ponteiros fornecem uma maneira eficiente de acessar e manipular dados sem a necessidade de operações complexas.
  • Eficiência e Segurança: Garantir que as operações sejam eficientes e seguras é crucial. A eficiência se refere ao tempo de execução e ao uso de recursos, enquanto a segurança envolve a prevenção de erros que podem levar a problemas como estouros de buffer e corrupção de memória.
  • Gerenciamento de Memória: As funções demonstram a importância do gerenciamento adequado da memória. Problemas como falta de espaço ou acessos inválidos podem levar a falhas de sistema e comportamentos inesperados.

Espero que esta explicação forneça uma compreensão mais profunda das operações e conceitos envolvidos na manipulação de strings e memória em C!

Parsing e Função ft_atoi

Parsing

O que é Parsing?

  • Definição: Parsing é o processo de analisar uma sequência de dados para extrair informações significativas e convertê-las em uma forma estruturada. Em programação, geralmente envolve a conversão de dados de um formato para outro, como converter uma string para um número.
  • Importância: Parsing é essencial para interpretar e processar dados de entrada em programas. Por exemplo, ao ler dados de um arquivo ou entrada do usuário, o parsing ajuda a converter essas informações em tipos de dados que o programa pode manipular e utilizar.

Função ft_atoi

Função: Converte uma string que representa um número decimal para um inteiro.

Implementação:

// Converte uma string para um inteiro
int ft_atoi(const char *str) {
int result = 0;
while (*str >= '0' && *str <= '9') {
result = result * 10 + (*str - '0');
str++;
}
return result;
}

Detalhes Internos:

  • Algoritmo:
    • Iteração: A função percorre cada caractere da string enquanto ele estiver dentro do intervalo de caracteres numéricos ('0' a '9').
    • Conversão: Para cada caractere numérico, a função atualiza o resultado multiplicando o valor atual por 10 e adicionando o valor do caractere convertido para inteiro (*str - '0').
    • Atualização da String: O ponteiro da string é incrementado para passar para o próximo caractere.
  • Complexidade: O tempo de execução é O(n), onde n é o número de caracteres na string até encontrar um caractere não numérico ou o final da string.
  • Aspectos de Memória: O parsing de uma string para um número é feito de forma incremental, manipulando cada caractere individualmente e acumulando o resultado.

Aspectos Computacionais:

  • Validação e Controle: A função ft_atoi assume que a string contém apenas caracteres numéricos válidos. Em uma aplicação mais completa, você deve adicionar verificações para lidar com entradas inválidas e sinais negativos, e também considerar o tratamento de possíveis estouros de inteiros.
  • Conversão de Dados: A função exemplifica como converter dados de uma representação textual para uma representação binária numérica, que é fundamental para muitas operações em programas.

Conceito Relacionado:

  • Representação Interna de Números: Em sistemas computacionais, números são representados em formato binário, e o parsing converte a representação textual (como uma string de caracteres) para esse formato binário interno. Isso é crucial para a interpretação correta e manipulação de dados numéricos dentro de um programa.

O intuito deste tutorial é ajudar você a entender melhor como é construída uma biblioteca em C e os conceitos subjacentes envolvidos.

🚀

Bora extendê-la?

A seguir, vou prototipar diversas novas funções em conjunto das anteriores. Happy coding!

1. Funções de Manipulação de Strings

1.1. ft_itoa

Função: Converte um número inteiro em uma string.

Detalhes Internos:

  • Algoritmo: Calcula o número de dígitos necessários e aloca memória para a string resultante. Converte cada dígito do número para seu equivalente em caractere e armazena na string.
  • Conceito: Conversão de tipo, manipulação de memória dinâmica.
char *ft_itoa(int n);

1.2. ft_strchr

Função: Encontra a primeira ocorrência de um caractere em uma string.

Detalhes Internos:

  • Algoritmo: Percorre a string até encontrar o caractere especificado. Retorna um ponteiro para a primeira ocorrência ou NULL se não encontrado.
  • Conceito: Busca linear em memória.
char *ft_strchr(const char *s, int c);

1.3. ft_strdup

Função: Duplica uma string alocando nova memória.

Detalhes Internos:

  • Algoritmo: Aloca memória suficiente para a string duplicada e usa ft_strcpy para copiar o conteúdo.
  • Conceito: Manipulação de memória dinâmica e cópia de strings.
char *ft_strdup(const char *s);

1.4. ft_strjoin

Função: Concatena duas strings em uma nova string.

Detalhes Internos:

  • Algoritmo: Aloca memória para a nova string, copia ambas as strings para a nova área e adiciona o caractere nulo.
  • Conceito: Manipulação de memória dinâmica e concatenação de strings.
char *ft_strjoin(char const *s1, char const *s2);

1.5. ft_strmapi

Função: Aplica uma função a cada caractere de uma string, retornando uma nova string.

Detalhes Internos:

  • Algoritmo: Aloca memória para a nova string e aplica a função fornecida a cada caractere.
  • Conceito: Manipulação de strings com funções callback.
char *ft_strmapi(char const *s, char (*f)(unsigned int, char));

1.6. ft_strnstr

Função: Encontra a primeira ocorrência de uma substring dentro de uma string, com um limite de comprimento.

Detalhes Internos:

  • Algoritmo: Pesquisa a substring dentro do limite especificado.
  • Conceito: Busca substring com controle de limite.
char *ft_strnstr(const char *big, const char *little, size_t len);

1.7. ft_strrchr

Função: Encontra a última ocorrência de um caractere em uma string.

Detalhes Internos:

  • Algoritmo: Percorre a string a partir do final para encontrar a última ocorrência do caractere.
  • Conceito: Busca linear em memória a partir do final.
char *ft_strrchr(const char *s, int c);

1.8. ft_strtrim

Função: Remove caracteres específicos do início e fim de uma string.

Detalhes Internos:

  • Algoritmo: Percorre a string para remover os caracteres definidos no conjunto.
  • Conceito: Manipulação de strings e busca de caracteres.
char *ft_strtrim(char const *s1, char const *set);

1.9. ft_substr

Função: Extrai uma substring de uma string original.

Detalhes Internos:

  • Algoritmo: Aloca memória para a nova substring e copia os caracteres a partir da posição de início até o comprimento especificado.
  • Conceito: Manipulação de memória e substrings.
char *ft_substr(char const *s, unsigned int start, size_t len);

1.10. ft_strndup

Função: Duplica os primeiros n caracteres de uma string.

Detalhes Internos:

  • Algoritmo: Aloca memória para a nova string e copia os primeiros n caracteres.
  • Conceito: Manipulação de memória e cópia de substrings.
char *ft_strndup(const char *s, size_t len);

1.11. ft_strcpy e ft_strncpy

Função: Copiam strings de uma localização para outra, com ft_strncpy limitando o número de caracteres copiados.

Detalhes Internos:

  • Algoritmo: Copia caracteres de uma string para outra, respeitando o limite em ft_strncpy.
  • Conceito: Manipulação de memória e controle de buffer.
char *ft_strcpy(char *dest, char *src);
char *ft_strncpy(char *dest, char *src, unsigned int n);

1.12. ft_split e ft_special_split

Função: Divide uma string em um array de substrings com base em um delimitador ou lógica especial.

Detalhes Internos:

  • Algoritmo: Aloca memória para o array de substrings e divide a string com base no delimitador ou lógica especial.
  • Conceito: Manipulação de strings e alocação dinâmica de memória.
char **ft_split(char const *s, char c);
char **ft_special_split(char const *s);

1.13. ft_strstr e ft_strnchr

Função: Busca por uma substring ou caractere em uma string, com um limite opcional.

Detalhes Internos:

  • Algoritmo: Pesquisa a string para encontrar a substring ou caractere.
  • Conceito: Busca em memória com limites.
int ft_strstr(char *str, char *to_find);
int ft_strnchr(char *str, char c, int len);

2. Funções de Conversão e Verificação

2.1. ft_atoi e ft_atol

Função: Converte uma string que representa um número decimal em um inteiro ou longo inteiro.

Detalhes Internos:

  • Algoritmo: Similar ao parsing descrito anteriormente, mas ft_atol lida com valores maiores.
  • Conceito: Conversão de tipo e parsing.
int ft_atoi(const char *nptr);
long int ft_atol(const char *nptr);

2.2. Funções de Verificação (ft_issign, ft_isalnum, ft_isalpha, ft_isascii, ft_isdigit, ft_isspace, ft_isprint)

Função: Verificam se um caractere corresponde a um tipo específico, como dígito, letra, espaço, etc.

Detalhes Internos:

  • Algoritmo: Compara o caractere com os intervalos de valores válidos para cada tipo.
  • Conceito: Verificação e validação de caracteres.
int ft_issign(char c);
int ft_isalnum(int c);
int ft_isalpha(int c);
int ft_isascii(int c);
int ft_isdigit(int c);
int ft_isspace(char c);
int ft_isprint(int c);

3. Funções de Manipulação de Memória

3.1. ft_bzero, ft_calloc, ft_free_matrix

Função: Manipulam memória, zerando ou alocando blocos, e liberando matrizes.

Detalhes Internos:

  • Algoritmo: ft_bzero zera uma área de memória, ft_calloc aloca e inicializa memória, ft_free_matrix libera memória de matrizes.
  • Conceito: Gerenciamento de memória.
void ft_bzero(void *s, size_t n);
void *ft_calloc(size_t nmemb, size_t size);
void ft_free_matrix(char **matrix);

3.2. ft_memchr, ft_memcpy, ft_memmove, ft_memset

Função: Manipulam áreas de memória de forma eficiente.

Detalhes Internos:

  • Algoritmo: ft_memchr busca um valor na memória, ft_memcpy e ft_memmove copiam blocos de memória, ft_memset define valores.
  • Conceito: Manipulação e controle de memória.
void *ft_memchr(const void *s, int c, size_t n);
void *ft_memcpy(void *dest, const void *src, size_t n);
void *ft_memmove(void *dest, const void *src, size_t n);
void *ft_memset(void *ptr, int value, size_t num);

4. Funções de Impressão e Formatação

4.1. ft_putchar_fd, ft_putstr_fd, ft_putendl_fd, ft_putnbr_fd, ft_printf_fd, ft_flags

Função: Imprimem caracteres, strings e números em um descritor de arquivo, e formatam strings.

Detalhes Internos:

  • Algoritmo: Usa funções de sistema para escrita em arquivos ou saídas padrão e manipula formatos e flags.
  • Conceito: Manipulação de saída e formatação de strings.
int ft_putchar_fd(char c, int fd);
int ft_putstr_fd(char *s, int fd);
void ft_putendl_fd(char *s, int fd);
void ft_putnbr_fd(int n, int fd);
int ft_printf_fd(int fd, const char *type_format, ...);
int ft_flags(int fd, char flag, va_list args);

5. Funções Adicionais

5.1. ft_striteri

Função: Aplica uma função a cada caractere de uma string, com índice.

Detalhes Internos:

  • Algoritmo: Itera sobre a string e aplica a função fornecida a cada caractere, incluindo o índice.
  • Conceito: Manipulação de strings com funções callback.
void ft_striteri(char *s, void (*f)(unsigned int, char*));

5.2. ft_strlcat, ft_strlcpy, ft_strlen, ft_strcat, ft_strcspn

Função: Manipulam e manipulam strings de várias maneiras, incluindo concatenação e cópia.

Detalhes Internos:

  • Algoritmo: Funções como ft_strlcat e ft_strlcpy manipulam buffers com tamanho seguro, ft_strlen calcula o comprimento de uma string, ft_strcat concatena strings, ft_strcspn encontra a primeira ocorrência de um caractere que não está em um conjunto.
  • Conceito: Manipulação segura e eficiente de strings.

size_t ft_strlcat(char *dst, const char *src, size_t size);
size_t ft_strlcpy(char *dst, const char *src, size_t size);
size_t ft_strlen(const char *s);
size_t ft_strcat(char *dst, const char *src);
size_t ft_strcspn(char *s, char *reject);